home *** CD-ROM | disk | FTP | other *** search
Text File | 1994-09-22 | 241.3 KB | 7,554 lines |
- {$A+,B-,D+,L+,N-,E-,O-,R-,S-,V-,G-,F-,I-,X-}
- {$M 16384,0,655360}
-
- {Programtool for the realization of fast animations on the VGA-graphic- }
- {card by: Kai Rohrbacher, 1988-1991, Turbo-Pascal 6.0 }
-
- { Features: }
-
- { - flickerfree animation by using page-flipping, watching retrace }
- { signals and usage of a special 256 color mode of the VGA }
- { - sprite movement in any pixel-increments you want }
- { - arbitrary background image for the animation }
- { - full use of the VGA's 256-color mode }
- { - several sprite display methods available: }
- { - sprites can be declared to be transparent with regard to the background}
- { or other sprites pixel by pixel }
- { - sprites can change their color depending on the underlying background }
- { image (-> shadow function) }
- { - pixel precise hit-detection routine for sprite collisions built in }
- { - correct clipping of sprites at the screen boundaries when moving on- or }
- { offscreen }
- { - up to 32767 different sprites (default: 1000) }
- { - up to 32767 sprites may be simultaneously active (default: 500) }
- { - maximal size of each sprite = 64k }
- { - maximal size of all loaded sprites only restricted by available memory }
- { - works with virtual coordinates in the range -16000..+16000, thus }
- { simple creation of horizontal/vertical "scrolling" applications }
- { - scrolling background image, too }
- { - several supporting routines to: draw lines (with built in clipping- }
- { algorithm), points and graphic-text (incl. clipping), automatic heap }
- { management for storing/loading sprites, handling background images, }
- { changing sprite display modes at runtime, adjustment for different }
- { CPU-clocks, ... }
-
- UNIT ANIVGA;
- INTERFACE
-
- USES CRT,DOS;
-
- CONST ANIVGAVersion=11; {version number}
- NMAX=499;
- XMAX=319;
- YMAX=199;
- LoadMAX=1000; {max. number of simultaneously active sprites }
- LINESIZE=(XMAX+1) DIV 4; {size of one row=80 bytes }
- PAGESIZE=(YMAX+1)*LINESIZE; {200 rows at 320/4 bytes each}
- BACKGNDPAGE=2;
- SCROLLPAGE=3;
-
- STATIC=0; {constants for background mode }
- SCROLLING=1;
-
- MaxTiles=10000; {max. number of background tiles }
- StartVirtualX:INTEGER=0; {upper left image corner }
- StartVirtualY:INTEGER=0;
-
- {supported display modes for sprites: }
- Display_NORMAL=0; {normal : transparent for color 0 }
- Display_FAST =1; {fast : don't take background into account}
- Display_SHADOW=2; {shadow : color lookup driven by background data}
- Display_SHADOWEXACT=3; {color 0 is transparent for shadows, too }
- Display_UNKNOWN=255;{error value}
-
- {error codes of the animation package: }
- Err_None=0;
- Err_NotEnoughMemory=1;
- Err_FileIO=2;
- Err_InvalidSpriteNumber=3;
- Err_NoSprite=4;
- Err_InvalidPageNumber=5;
- Err_NoVGA=6;
- Err_NoPicture=7;
- Err_InvalidPercentage=8;
- Err_NoTile=9;
- Err_InvalidTileNumber=10;
- Err_InvalidCoordinates=11;
- Err_BackgroundToBig=12;
- Err_InvalidMode=13;
- Err_InvalidSpriteLoadNumber=14;
- Err_NoPalette=15;
- Err_PaletteWontFit=16;
- Err_InvalidFade=17;
-
- TYPE FontChar=ARRAY[0..5] OF BYTE;
- Font=ARRAY[0..255] OF Fontchar;
- FontOrient=(horizontal,vertical); {possible text directions }
- CONST GraphTextOrientation:FontOrient=horizontal; {actual output direction }
- GraphTextColor:BYTE=white; {actual text color }
- GraphTextBackground:BYTE=white;
- FontHeight=6;
- FontWidth=6;
-
- TYPE Table=ARRAY[0..NMAX] OF INTEGER;
- ColorTable=ARRAY[0..255] OF BYTE;
-
- TYPE PaletteEntry=RECORD red,green,blue:BYTE END;
- Palette=ARRAY[0..255] OF PaletteEntry;
- PalettePtr=^Palette;
-
- CONST DefaultColors:Palette= {default palette colors of 256color mode}
- ( {read out by using the VGA-BIOS-calls: }
- (red: 0; green: 0; blue: 0), { MOV AX,1017h ;read palette registers}
- (red: 0; green: 0; blue: 42), { XOR BX,BX ;start with color 0 }
- (red: 0; green: 42; blue: 0), { MOV CX,100h ;all 256 colors }
- (red: 0; green: 42; blue: 42), { LES DX,Ziel ;to ES:DX }
- (red: 42; green: 0; blue: 0), { INT 10h }
- (red: 42; green: 0; blue: 42), {Attention! These values can/could be }
- (red: 42; green: 21; blue: 0), {read out directly from the VGA card not}
- (red: 42; green: 42; blue: 42), {until a graphic mode has been activated; }
- (red: 21; green: 21; blue: 21), {thus, here they were defined "static"}
- (red: 21; green: 21; blue: 63),
- (red: 21; green: 63; blue: 21),
- (red: 21; green: 63; blue: 63),
- (red: 63; green: 21; blue: 21),
- (red: 63; green: 21; blue: 63),
- (red: 63; green: 63; blue: 21),
- (red: 63; green: 63; blue: 63),
- (red: 0; green: 0; blue: 0),
- (red: 5; green: 5; blue: 5),
- (red: 8; green: 8; blue: 8),
- (red: 11; green: 11; blue: 11),
- (red: 14; green: 14; blue: 14),
- (red: 17; green: 17; blue: 17),
- (red: 20; green: 20; blue: 20),
- (red: 24; green: 24; blue: 24),
- (red: 28; green: 28; blue: 28),
- (red: 32; green: 32; blue: 32),
- (red: 36; green: 36; blue: 36),
- (red: 40; green: 40; blue: 40),
- (red: 45; green: 45; blue: 45),
- (red: 50; green: 50; blue: 50),
- (red: 56; green: 56; blue: 56),
- (red: 63; green: 63; blue: 63),
- (red: 0; green: 0; blue: 63),
- (red: 16; green: 0; blue: 63),
- (red: 31; green: 0; blue: 63),
- (red: 47; green: 0; blue: 63),
- (red: 63; green: 0; blue: 63),
- (red: 63; green: 0; blue: 47),
- (red: 63; green: 0; blue: 31),
- (red: 63; green: 0; blue: 16),
- (red: 63; green: 0; blue: 0),
- (red: 63; green: 16; blue: 0),
- (red: 63; green: 31; blue: 0),
- (red: 63; green: 47; blue: 0),
- (red: 63; green: 63; blue: 0),
- (red: 47; green: 63; blue: 0),
- (red: 31; green: 63; blue: 0),
- (red: 16; green: 63; blue: 0),
- (red: 0; green: 63; blue: 0),
- (red: 0; green: 63; blue: 16),
- (red: 0; green: 63; blue: 31),
- (red: 0; green: 63; blue: 47),
- (red: 0; green: 63; blue: 63),
- (red: 0; green: 47; blue: 63),
- (red: 0; green: 31; blue: 63),
- (red: 0; green: 16; blue: 63),
- (red: 31; green: 31; blue: 63),
- (red: 39; green: 31; blue: 63),
- (red: 47; green: 31; blue: 63),
- (red: 55; green: 31; blue: 63),
- (red: 63; green: 31; blue: 63),
- (red: 63; green: 31; blue: 55),
- (red: 63; green: 31; blue: 47),
- (red: 63; green: 31; blue: 39),
- (red: 63; green: 31; blue: 31),
- (red: 63; green: 39; blue: 31),
- (red: 63; green: 47; blue: 31),
- (red: 63; green: 55; blue: 31),
- (red: 63; green: 63; blue: 31),
- (red: 55; green: 63; blue: 31),
- (red: 47; green: 63; blue: 31),
- (red: 39; green: 63; blue: 31),
- (red: 31; green: 63; blue: 31),
- (red: 31; green: 63; blue: 39),
- (red: 31; green: 63; blue: 47),
- (red: 31; green: 63; blue: 55),
- (red: 31; green: 63; blue: 63),
- (red: 31; green: 55; blue: 63),
- (red: 31; green: 47; blue: 63),
- (red: 31; green: 39; blue: 63),
- (red: 45; green: 45; blue: 63),
- (red: 49; green: 45; blue: 63),
- (red: 54; green: 45; blue: 63),
- (red: 58; green: 45; blue: 63),
- (red: 63; green: 45; blue: 63),
- (red: 63; green: 45; blue: 58),
- (red: 63; green: 45; blue: 54),
- (red: 63; green: 45; blue: 49),
- (red: 63; green: 45; blue: 45),
- (red: 63; green: 49; blue: 45),
- (red: 63; green: 54; blue: 45),
- (red: 63; green: 58; blue: 45),
- (red: 63; green: 63; blue: 45),
- (red: 58; green: 63; blue: 45),
- (red: 54; green: 63; blue: 45),
- (red: 49; green: 63; blue: 45),
- (red: 45; green: 63; blue: 45),
- (red: 45; green: 63; blue: 49),
- (red: 45; green: 63; blue: 54),
- (red: 45; green: 63; blue: 58),
- (red: 45; green: 63; blue: 63),
- (red: 45; green: 58; blue: 63),
- (red: 45; green: 54; blue: 63),
- (red: 45; green: 49; blue: 63),
- (red: 0; green: 0; blue: 28),
- (red: 7; green: 0; blue: 28),
- (red: 14; green: 0; blue: 28),
- (red: 21; green: 0; blue: 28),
- (red: 28; green: 0; blue: 28),
- (red: 28; green: 0; blue: 21),
- (red: 28; green: 0; blue: 14),
- (red: 28; green: 0; blue: 7),
- (red: 28; green: 0; blue: 0),
- (red: 28; green: 7; blue: 0),
- (red: 28; green: 14; blue: 0),
- (red: 28; green: 21; blue: 0),
- (red: 28; green: 28; blue: 0),
- (red: 21; green: 28; blue: 0),
- (red: 14; green: 28; blue: 0),
- (red: 7; green: 28; blue: 0),
- (red: 0; green: 28; blue: 0),
- (red: 0; green: 28; blue: 7),
- (red: 0; green: 28; blue: 14),
- (red: 0; green: 28; blue: 21),
- (red: 0; green: 28; blue: 28),
- (red: 0; green: 21; blue: 28),
- (red: 0; green: 14; blue: 28),
- (red: 0; green: 7; blue: 28),
- (red: 14; green: 14; blue: 28),
- (red: 17; green: 14; blue: 28),
- (red: 21; green: 14; blue: 28),
- (red: 24; green: 14; blue: 28),
- (red: 28; green: 14; blue: 28),
- (red: 28; green: 14; blue: 24),
- (red: 28; green: 14; blue: 21),
- (red: 28; green: 14; blue: 17),
- (red: 28; green: 14; blue: 14),
- (red: 28; green: 17; blue: 14),
- (red: 28; green: 21; blue: 14),
- (red: 28; green: 24; blue: 14),
- (red: 28; green: 28; blue: 14),
- (red: 24; green: 28; blue: 14),
- (red: 21; green: 28; blue: 14),
- (red: 17; green: 28; blue: 14),
- (red: 14; green: 28; blue: 14),
- (red: 14; green: 28; blue: 17),
- (red: 14; green: 28; blue: 21),
- (red: 14; green: 28; blue: 24),
- (red: 14; green: 28; blue: 28),
- (red: 14; green: 24; blue: 28),
- (red: 14; green: 21; blue: 28),
- (red: 14; green: 17; blue: 28),
- (red: 20; green: 20; blue: 28),
- (red: 22; green: 20; blue: 28),
- (red: 24; green: 20; blue: 28),
- (red: 26; green: 20; blue: 28),
- (red: 28; green: 20; blue: 28),
- (red: 28; green: 20; blue: 26),
- (red: 28; green: 20; blue: 24),
- (red: 28; green: 20; blue: 22),
- (red: 28; green: 20; blue: 20),
- (red: 28; green: 22; blue: 20),
- (red: 28; green: 24; blue: 20),
- (red: 28; green: 26; blue: 20),
- (red: 28; green: 28; blue: 20),
- (red: 26; green: 28; blue: 20),
- (red: 24; green: 28; blue: 20),
- (red: 22; green: 28; blue: 20),
- (red: 20; green: 28; blue: 20),
- (red: 20; green: 28; blue: 22),
- (red: 20; green: 28; blue: 24),
- (red: 20; green: 28; blue: 26),
- (red: 20; green: 28; blue: 28),
- (red: 20; green: 26; blue: 28),
- (red: 20; green: 24; blue: 28),
- (red: 20; green: 22; blue: 28),
- (red: 0; green: 0; blue: 16),
- (red: 4; green: 0; blue: 16),
- (red: 8; green: 0; blue: 16),
- (red: 12; green: 0; blue: 16),
- (red: 16; green: 0; blue: 16),
- (red: 16; green: 0; blue: 12),
- (red: 16; green: 0; blue: 8),
- (red: 16; green: 0; blue: 4),
- (red: 16; green: 0; blue: 0),
- (red: 16; green: 4; blue: 0),
- (red: 16; green: 8; blue: 0),
- (red: 16; green: 12; blue: 0),
- (red: 16; green: 16; blue: 0),
- (red: 12; green: 16; blue: 0),
- (red: 8; green: 16; blue: 0),
- (red: 4; green: 16; blue: 0),
- (red: 0; green: 16; blue: 0),
- (red: 0; green: 16; blue: 4),
- (red: 0; green: 16; blue: 8),
- (red: 0; green: 16; blue: 12),
- (red: 0; green: 16; blue: 16),
- (red: 0; green: 12; blue: 16),
- (red: 0; green: 8; blue: 16),
- (red: 0; green: 4; blue: 16),
- (red: 8; green: 8; blue: 16),
- (red: 10; green: 8; blue: 16),
- (red: 12; green: 8; blue: 16),
- (red: 14; green: 8; blue: 16),
- (red: 16; green: 8; blue: 16),
- (red: 16; green: 8; blue: 14),
- (red: 16; green: 8; blue: 12),
- (red: 16; green: 8; blue: 10),
- (red: 16; green: 8; blue: 8),
- (red: 16; green: 10; blue: 8),
- (red: 16; green: 12; blue: 8),
- (red: 16; green: 14; blue: 8),
- (red: 16; green: 16; blue: 8),
- (red: 14; green: 16; blue: 8),
- (red: 12; green: 16; blue: 8),
- (red: 10; green: 16; blue: 8),
- (red: 8; green: 16; blue: 8),
- (red: 8; green: 16; blue: 10),
- (red: 8; green: 16; blue: 12),
- (red: 8; green: 16; blue: 14),
- (red: 8; green: 16; blue: 16),
- (red: 8; green: 14; blue: 16),
- (red: 8; green: 12; blue: 16),
- (red: 8; green: 10; blue: 16),
- (red: 11; green: 11; blue: 16),
- (red: 12; green: 11; blue: 16),
- (red: 13; green: 11; blue: 16),
- (red: 15; green: 11; blue: 16),
- (red: 16; green: 11; blue: 16),
- (red: 16; green: 11; blue: 15),
- (red: 16; green: 11; blue: 13),
- (red: 16; green: 11; blue: 12),
- (red: 16; green: 11; blue: 11),
- (red: 16; green: 12; blue: 11),
- (red: 16; green: 13; blue: 11),
- (red: 16; green: 15; blue: 11),
- (red: 16; green: 16; blue: 11),
- (red: 15; green: 16; blue: 11),
- (red: 13; green: 16; blue: 11),
- (red: 12; green: 16; blue: 11),
- (red: 11; green: 16; blue: 11),
- (red: 11; green: 16; blue: 12),
- (red: 11; green: 16; blue: 13),
- (red: 11; green: 16; blue: 15),
- (red: 11; green: 16; blue: 16),
- (red: 11; green: 15; blue: 16),
- (red: 11; green: 13; blue: 16),
- (red: 11; green: 12; blue: 16),
- (red: 0; green: 0; blue: 0),
- (red: 0; green: 0; blue: 0),
- (red: 0; green: 0; blue: 0),
- (red: 0; green: 0; blue: 0),
- (red: 0; green: 0; blue: 0),
- (red: 0; green: 0; blue: 0),
- (red: 0; green: 0; blue: 0),
- (red: 0; green: 0; blue: 0)
- );
-
- VAR Error:BYTE; {global error variable }
- SpriteN:Table;
- SpriteX:Table;
- SpriteY:Table;
- NextSprite:ARRAY[0..LoadMAX] OF WORD;
- SPRITEAD:ARRAY[0..LoadMAX] OF WORD;
- PAGE,PAGEADR,SCROLLADR,BACKGNDADR:WORD;
- Color:BYTE; {drawing color for lines }
- ActualColors:Palette; {actual color palette}
- was_cut:BOOLEAN; {TRUE/FALSE, if "GetImage" had to clip image }
- left_cut, {variables set by "GetImage"; if "was_cut" has}
- right_cut, {been set to TRUE, they will report, where and }
- top_cut, {and how much of the image had to been clipped }
- bottom_cut:WORD; {off }
-
- BackgroundMode:BYTE;
- BackTile:ARRAY[0..MaxTiles] OF BYTE; {tile memory }
- XTiles,YTiles:INTEGER; {width, height of defined area }
- BackX1,BackY1,BackX2,BackY2:INTEGER; {coordinates of the defined area }
-
- CONST Fade_Squares =0;
- Fade_Moiree1 =1;
- Fade_Moiree2 =2;
- Fade_Moiree3 =3;
- Fade_Moiree4 =4;
- Fade_Moiree5 =5;
- Fade_Moiree6 =6;
- Fade_Moiree7 =7;
- Fade_Moiree8 =8;
- Fade_Moiree9 =9;
- Fade_Moiree10=10;
- Fade_Moiree11=11;
- Fade_Moiree12=12;
- Fade_Moiree13=13;
- Fade_Moiree14=14;
- Fade_SweepInFromTop=15;
- Fade_SweepInFromBottom=16;
- Fade_SweepInFromLeft=17;
- Fade_SweepInFromRight=18;
- Fade_ScrollInFromTop=19;
- Fade_ScrollInFromBottom=20;
- Fade_ScrollInFromLeft=21;
- Fade_ScrollInFromRight=22;
- Fade_Circles =23;
-
- PROCEDURE ShadowTab;
- PROCEDURE SetShadowTab(brightness:BYTE);
- PROCEDURE SetPalette(pal:Palette; update:BOOLEAN);
- PROCEDURE GetPalette(VAR pal:Palette);
- FUNCTION LoadPalette(name:String; number:BYTE; VAR pal:Palette):WORD;
- PROCEDURE SetCycleTime(milliseconds:WORD);
- PROCEDURE SetSpriteCycle(nr,len:WORD);
- FUNCTION GetImage(x1,y1,x2,y2:INTEGER; pa:BYTE):POINTER;
- PROCEDURE PutImage(x,y:INTEGER; p:POINTER; pa:BYTE);
- PROCEDURE FreeImageMem(p:POINTER);
- PROCEDURE InitGraph;
- PROCEDURE Screen(pa:BYTE);
- PROCEDURE Line(x1,y1,x2,y2:INTEGER; pa:BYTE);
- PROCEDURE BackgroundLine(x1,y1,x2,y2:INTEGER);
- FUNCTION GetPixel(x,y:INTEGER):BYTE;
- FUNCTION BackgroundGetPixel(x,y:INTEGER):BYTE;
- FUNCTION PageGetPixel(x,y:INTEGER; pa:BYTE):BYTE;
- PROCEDURE PutPixel(x,y:INTEGER; color:Byte);
- PROCEDURE BackgroundPutPixel(x,y:INTEGER; color:Byte);
- PROCEDURE PagePutPixel(x,y:INTEGER; color,pa:Byte);
- PROCEDURE OutTextXY(x,y:INTEGER; pa:BYTE; s:STRING);
- PROCEDURE BackgroundOutTextXY(x,y:INTEGER; s:STRING);
- FUNCTION Hitdetect(s1,s2:INTEGER):BOOLEAN;
- PROCEDURE Animate;
- FUNCTION LoadSprite(name:String; number:WORD):WORD;
- FUNCTION LoadTile(name:STRING; number:BYTE):WORD;
- PROCEDURE SetBackgroundScrollRange(x1,y1,x2,y2:INTEGER);
- PROCEDURE SetBackgroundMode(mode:BYTE);
- PROCEDURE PutTile(x,y:INTEGER; TileNr:BYTE);
- PROCEDURE SetOffscreenTile(TileNr:BYTE);
- PROCEDURE SetModeByte(Sp:WORD; M:BYTE);
- FUNCTION GetModeByte(Sp:WORD):BYTE;
- PROCEDURE FillPage(pa,color:Byte);
- PROCEDURE FillBackground(color:BYTE);
- PROCEDURE GetBackgroundFromPage(pa:Byte);
- PROCEDURE WritePage(name:STRING; pa:BYTE);
- PROCEDURE LoadPage(name:STRING; pa:BYTE);
- PROCEDURE WriteBackgroundPage(name:STRING);
- PROCEDURE LoadBackgroundPage(name:STRING);
- PROCEDURE FadeIn(pa,ti,style:WORD);
- PROCEDURE InitRoutines;
- PROCEDURE CloseRoutines;
- FUNCTION GetErrorMessage:STRING;
-
-
- {--------------------------------------------------------------------------}
-
- IMPLEMENTATION
-
- CONST StartIndex=0;
- EndIndex=StartIndex+3;
- {offset addresses of the graphic pages (in segment $A000):}
- Offset_Adr:Array[StartIndex..EndIndex] OF WORD=($0000,$3E80,$7D00,$BB80);
- {segment addresses of graphic pages (with offset = 0):}
- Segment_Adr:ARRAY[StartIndex..EndIndex] OF WORD=($A000,$A3E8,$A7D0,$ABB8);
-
- {sprite header format:}
-
- { 0..1 DW offset_ptr_to_plane0_data}
- { 2..3 DW offset_ptr_to_plane1_data}
- { 4..5 DW offset_ptr_to_plane2_data}
- { 6..7 DW offset_ptr_to_plane3_data}
- { 8..9 DW width (in groups of 4) (in German: "Breite")}
- { 10..11 DW heigth in rows (in German: "Hoehe")}
- { 12..15 DB 1,2,4,8 ; translate-table used for port-accesses }
- { 16..17 DW SpriteLength ; length of this sprite in bytes}
- { ; now follows the scratch area reserved for temporary}
- { ; variables: ("a|b" = used for a and b)}
- { 18..19 DW ? ; licutoff_ | hit1xfirst}
- { 20..21 DW ? ; zeilenadr | hit1yfirst}
- { 22..23 DW ? ; bildx | hit2xfirst}
- { 24..25 DW ? ; yoffset_ | hit2yfirst}
- { 26..27 DW ? ; end_min_start | ueberlappx_1}
- { 28..29 DW ? ; | ueberlappy_1}
- { 30..31 DW ? ; | x1}
- { 32..33 DW ? ; | x2}
- { 34..35 DW ? ; | y1}
- { 36..37 DW ? ; | y2}
- { 38..39 DB 'K','R' ; tag used for sprites}
- { 40 DB 1 ; version number}
- { 41 DB 0 ; display mode used for sprite}
- { 42..43 DW offset_ptr_to_left_boundary_data}
- { 44..45 DW offset_ptr_to_right_boundary_data}
- { 46..47 DW offset_ptr_to_top_boundary_data}
- { 48..49 DW offset_ptr_to_bottom_boundary_data}
- { 50..?? DB data }
-
- { for ex.: xxrxxxxx, with: r=red=40, g=green=45, b=blue=35, x=white=30}
- { xrgrxxxx}
- { rbgbrxxx}
- { }
-
- {addresses of important values inside the sprite header: }
- Left=42;
- Right=44;
- Top=46;
- Bottom=48;
- Breite=8;
- Hoehe=10;
- Translate=12;
- SpriteLength=16;
- Kennung=38;
- Version=40;
- Modus=41;
-
- {addresses of temporary variables for the drawing routines: }
- licutoff_=18;
- zeilenadr=20;
- bildx=22;
- yoffset_=24;
- end_min_start=26;
-
- {addresses of temporary variables for the collision detection routine:}
- hit1xfirst=18;
- hit1yfirst=20;
- hit2xfirst=22;
- hit2yfirst=24;
- ueberlappx_1=26;
- ueberlappy_1=28;
- x1=30;
- x2=32;
- y1=34;
- y2=36;
-
- TranslateTab:ARRAY[0..3] OF BYTE=(1,2,4,8); {For mask addressing }
- PICHeader:STRING[3]='PIC'; {tag in picture files }
- Schatten :BYTE=70; {default brightness of shadows }
-
- TYPE SpriteHeader= RECORD
- Zeiger_auf_Plane:Array[0..3] OF Word;
- Breite_in_4er_Gruppen:WORD;
- Hoehe_in_Zeilen:WORD;
- Translate:Array[1..4] OF Byte;
- SpriteLength:WORD;
- Dummy:Array[1..10] OF Word;
- Kennung:ARRAY[1..2] OF CHAR;
- Version:BYTE;
- Modus:BYTE;
- ZeigerL,ZeigerR,ZeigerO,ZeigerU:Word;
- END;
-
- CONST FontMask:ARRAY[0..7] OF BYTE=($80,$40,$20,$10,8,4,2,1);
- FontData: Font=( {used font: }
- ( 0, 0, 0, 0, 0, 0), {#0} {selfmade 6x6 font (ugly..)}
- ( 0,216, 0,248,112, 0), {#1}
- (248,168,248,136,216,248), {#2}
- ( 0, 80,248,248,112, 32), {#3}
- ( 0, 32,112,248,112, 32), {#4}
- ( 32,112,216,248, 32,112), {#5}
- ( 32,112,248,248, 32,112), {#6}
- ( 0, 32,216,216, 32, 0), {#7}
- (248,216,168,168,216,248), {#8}
- ( 0,112,200,152,112, 0), {#9}
- (248,136,168,168,136,248), {#10}
- ( 56, 24, 32,112,136,112), {#11}
- (112,136,112, 32,248, 32), {#12}
- ( 56, 40, 32, 32,224,224), {#13}
- ( 0,120, 72,120, 72,216), {#14}
- ( 0, 32,168, 80,168, 32), {#15}
- ( 0,128,224,248,224,128), {#16}
- ( 0, 8, 56,248, 56, 8), {#17}
- ( 32,112,168,168,112, 32), {#18}
- ( 0,216,216,216, 0,216), {#19}
- ( 0,120,168,104, 40, 40), {#20}
- ( 24, 32, 16, 40,144, 96), {#21}
- ( 0, 0, 0, 0,248,248), {#22}
- ( 32,112, 32,112, 32,248), {#23}
- ( 0, 32,112,248, 32, 32), {#24}
- ( 0, 32, 32,248,112, 32), {#25}
- ( 0, 32, 16,248, 16, 32), {#26}
- ( 0, 32, 64,248, 64, 32), {#27}
- ( 0, 0,192,248, 0, 0), {#28}
- ( 0, 0, 80,248, 80, 0), {#29}
- ( 0, 0, 0, 32,112,248), {#30}
- ( 0, 0,248,112, 32, 0), {#31}
- ( 0, 0, 0, 0, 0, 0), { }
- ( 0, 48, 48, 48, 0, 48), {!}
- ( 0, 80, 80, 0, 0, 0), {"}
- ( 0, 80,248, 80,248, 80), {#}
- ( 32,120,160,112, 40,240), { $}
- ( 0,200, 16, 32, 64,152), {%}
- ( 0,112,216,112,152,104), {&}
- ( 0, 16, 32, 0, 0, 0), {'}
- ( 0,112,192,192,192,112), {(}
- ( 0,224, 48, 48, 48,224), {)}
- ( 0, 80, 32,248, 32, 80), {*}
- ( 0, 0, 32,248, 32, 0), {+}
- ( 0, 0, 0, 32, 32, 64), {,}
- ( 0, 0, 0,248, 0, 0), {-}
- ( 0, 0, 0, 0, 48, 0), {.}
- ( 4, 8, 16, 32, 64,128), {/}
- ( 0,112,152,168,200,112), {0}
- ( 0, 48,112, 48, 48,120), {1}
- ( 0,240, 24,112,192,248), {2}
- ( 0,240, 24,112, 24,240), {3}
- ( 0,192,208,248, 48, 48), {4}
- ( 0,248,192,240, 24,240), {5}
- ( 0,248,128,248,136,248), {6}
- ( 0,248, 24, 48, 96, 96), {7}
- ( 0,112,216,112,216,112), {8}
- ( 0,112,136,120, 8,112), {9}
- ( 0, 0, 32, 0, 32, 0), {:}
- ( 0, 0, 32, 0, 32, 64), {;}
- ( 0, 24, 48, 96, 48, 24), {<}
- ( 0, 0,248, 0,248, 0), {=}
- ( 0, 96, 48, 24, 48, 96), {>}
- (112,136, 16, 32, 0, 32), {?}
- ( 0,112,136,184,128,120), {@}
- ( 0,112,200,248,200,200), {A}
- ( 0,240,200,240,200,240), {B}
- ( 0,120,192,192,192,120), {C}
- ( 0,240,216,200,216,240), {D}
- ( 0,248,192,240,192,248), {E}
- ( 0,248,192,240,192,192), {F}
- ( 0,120,192,216,200,120), {G}
- ( 0,200,200,248,200,200), {H}
- ( 0,120, 48, 48, 48,120), {I}
- ( 0,248, 8, 8,200,112), {J}
- ( 0,200,208,224,208,200), {K}
- ( 0,192,192,192,192,248), {L}
- ( 0,136,216,168,136,136), {M}
- ( 0,136,200,168,152,136), {N}
- ( 0,112,200,200,200,112), {O}
- ( 0,240,200,240,192,192), {P}
- ( 0, 96,208,208,208,104), {Q}
- ( 0,240,136,240,208,200), {R}
- ( 0,248,192,248, 24,248), {S}
- ( 0,248, 96, 96, 96, 96), {T}
- ( 0,200,200,200,200,248), {U}
- ( 0,200,200,200,200, 48), {V}
- ( 0,136,136,168,248, 80), {W}
- ( 0,136,216,112,216,136), {X}
- ( 0,200,200,112, 48, 48), {Y}
- ( 0,248, 24,112,192,248), {Z}
- ( 0,120, 96, 96, 96,120), {[}
- (128, 64, 32, 16, 8, 4), {\}
- ( 0,120, 24, 24, 24,120), {]}
- ( 32, 80,136, 0, 0, 0), {^}
- ( 0, 0, 0, 0, 0,248), {_}
- ( 64, 32, 0, 0, 0, 0), {`}
- ( 0, 0,112,200,200,120), {a}
- ( 0,128,240,136,136,240), {b}
- ( 0, 0,120,192,192,120), {c}
- ( 0, 8,120,136,136,120), {d}
- ( 0, 0,112,248,128,112), {e}
- ( 0, 24, 32,120, 32, 32), {f}
- ( 0,112,136,120, 8,112), {g}
- ( 0,192,240,200,200,200), {h}
- ( 48, 0, 48, 48, 48, 48), {i}
- ( 24, 0, 24, 24,216,112), {j}
- ( 0,192,208,224,216,216), {k}
- ( 0, 96, 96, 96, 96, 56), {l}
- ( 0, 0,208,248,168,136), {m}
- ( 0, 0,240,200,200,200), {n}
- ( 0, 0,112,200,200,112), {o}
- ( 0, 0,240,200,240,192), {p}
- ( 0, 0,112,152,120, 24), {q}
- ( 0, 0,176,104, 96, 96), {r}
- ( 0, 56, 64, 48,136,112), {s}
- ( 0, 96,248, 96,104, 48), {t}
- ( 0, 0,200,200,200,120), {u}
- ( 0, 0,200,200,200,112), {v}
- ( 0, 0,136,168,168,112), {w}
- ( 0, 0,216, 96, 48,216), {x}
- ( 0, 0,200,248, 8,112), {y}
- ( 0, 0,240, 48,192,248), {z}
- ( 0, 56, 96,192, 96, 56),(*{*)
- ( 0, 16, 16, 0, 16, 16), {|}
- ( 0,224, 48, 24, 48,224),(*}*)
- ( 0,104,144, 0, 0, 0), {~}
- ( 0, 32, 80,136,248, 0), {#127}
- (112,200,128,200,112,192), {#128}
- ( 0,200, 0,200,200,120), {#129}
- ( 24, 32,112,248,128,112), {#130}
- ( 16, 40, 0,120,196,124), {#131}
- (104, 0,112,200,200,120), {#132}
- ( 48, 8,112,136,136,120), {#133}
- ( 16, 40, 16,112,200,120), {#134}
- ( 0,120,192,120, 16, 96), {#135}
- (112, 0,112,248,192,112), {#136}
- ( 80, 0,112,248,128,112), {#137}
- ( 48, 8,112,248,192,112), {#138}
- (104, 0, 48, 48, 48, 48), {#139}
- ( 48, 72, 0, 48, 48, 48), {#140}
- ( 96, 16, 0, 48, 48, 48), {#141}
- (200, 0,112,200,248,200), {#142}
- ( 48, 0,112,200,248,200), {#143}
- (112,248,192,240,192,248), {#144}
- ( 0,208, 40,112,160, 88), {#145}
- ( 0, 56, 80,248,144,152), {#146}
- ( 32, 80, 0,112,200,112), {#147}
- ( 80, 0,112,200,200,112), {#148}
- ( 96, 16, 0,112,200,112), {#149}
- ( 32, 80, 0,200,200,120), {#150}
- ( 96, 16, 0,200,200,120), {#151}
- ( 80, 0,200,248, 8,112), {#152}
- ( 80, 0,112,200,200,112), {#153}
- (200, 0,200,200,200,248), {#154}
- ( 16,120,128,128,120, 16), {#155}
- ( 48, 72,224, 64,136,248), {#156}
- (216, 32,248, 32,248, 32), {#157}
- (192,160,208,184,144,152), {#158}
- ( 48, 40, 96, 48,160, 96), {#159}
- ( 48, 64, 0,112,136,120), {#160}
- ( 48, 64, 0, 32, 32, 32), {#161}
- ( 48, 64, 0,112,200,112), {#162}
- ( 48, 64, 0,200,200,120), {#163}
- (104,144, 0,176, 72, 72), {#164}
- (104,144, 0,200,168,152), {#165}
- (112,144,104, 0,248, 0), {#166}
- (112,136,112, 0,248, 0), {#167}
- ( 32, 0, 32, 64,136,112), {#168}
- ( 0, 0,252,192, 0, 0), {#169}
- ( 0, 0,252, 12, 0, 0), {#170}
- ( 72, 80, 32, 64,168, 40), {#171}
- ( 72, 80, 32, 80,152, 8), {#172}
- ( 48, 0, 48, 48, 48, 0), {#173}
- ( 40, 80,160, 80, 40, 0), {#174}
- (160, 80, 40, 80,160, 0), {#175}
- ( 84,168, 84,168, 84,168), {#176}
- (252,252,252,252,252,252), {#177}
- (168, 84,168, 84,168, 84), {#178}
- ( 16, 16, 16, 16, 16, 16), {#179}
- ( 16, 16, 16,240, 16, 16), {#180}
- ( 16, 16,240, 16,240, 16), {#181}
- ( 40, 40, 40,232, 40, 40), {#182}
- ( 0, 0, 0,248, 40, 40), {#183}
- ( 0, 0,240, 16,240, 16), {#184}
- ( 40, 40,232, 8,232, 40), {#185}
- ( 40, 40, 40, 40, 40, 40), {#186}
- ( 0, 0,248, 8,232, 40), {#187}
- ( 40, 40,232, 8,248, 0), {#188}
- ( 40, 40, 40,248, 0, 0), {#189}
- ( 16, 16,240, 16,240, 0), {#190}
- ( 0, 0, 0,240, 16, 16), {#191}
- ( 16, 16, 16, 28, 0, 0), {#192}
- ( 16, 16, 16,252, 0, 0), {#193}
- ( 0, 0, 0,252, 16, 16), {#194}
- ( 16, 16, 16, 28, 16, 16), {#195}
- ( 0, 0, 0,252, 0, 0), {#196}
- ( 16, 16, 16,252, 16, 16), {#197}
- ( 16, 16, 28, 16, 28, 16), {#198}
- ( 40, 40, 40, 44, 40, 40), {#199}
- ( 40, 40, 44, 32, 60, 0), {#200}
- ( 0, 0, 60, 32, 44, 40), {#201}
- ( 40, 40,236, 0,252, 0), {#202}
- ( 0, 0,252, 0,236, 40), {#203}
- ( 40, 40, 44, 32, 44, 40), {#204}
- ( 0, 0,252, 0,252, 0), {#205}
- ( 40, 40,236, 0,236, 40), {#206}
- ( 16, 16,252, 0,252, 0), {#207}
- ( 40, 40, 40,252, 0, 0), {#208}
- ( 0, 0,252, 0,252, 16), {#209}
- ( 0, 0, 0,252, 40, 40), {#210}
- ( 40, 40, 40, 60, 0, 0), {#211}
- ( 16, 16, 28, 16, 28, 0), {#212}
- ( 0, 0, 28, 16, 28, 16), {#213}
- ( 0, 0, 0, 60, 40, 40), {#214}
- ( 40, 40, 40,252, 40, 40), {#215}
- ( 16, 16,252, 16,252, 16), {#216}
- ( 16, 16, 16,240, 0, 0), {#217}
- ( 0, 0, 28, 16, 16, 16), {#218}
- (252,252,252,252,252,252), {#219}
- ( 0, 0, 0,252,252,252), {#220}
- (192,192,192,192,192,192), {#221}
- ( 12, 12, 12, 12, 12, 12), {#222}
- (252,252,252, 0, 0, 0), {#223}
- ( 0, 0,104,144,144,104), {#224}
- ( 0,112,152,176,136,176), {#225}
- ( 0,248,136,128,128,128), {#226}
- ( 0, 0,248, 80, 80, 80), {#227}
- (248, 72, 32, 64,136,248), {#228}
- ( 0, 0,120,144,144, 96), {#229}
- ( 0, 72, 72,120, 64,192), {#230}
- ( 0, 0,104,176, 32, 32), {#231}
- ( 0,248, 32, 80, 32,248), {#232}
- ( 0,112,136,248,136,112), {#233}
- ( 0,112,136,136, 80,216), {#234}
- ( 56, 64, 32,112,136,112), {#235}
- ( 0, 0, 80,168, 80, 0), {#236}
- ( 0, 8, 80,168, 80,128), {#237}
- ( 0,120,128,248,128,120), {#238}
- ( 0, 0,112,136,136,136), {#239}
- ( 0,248, 0,248, 0,248), {#240}
- ( 0, 32,112, 32, 0,248), {#241}
- ( 64, 32, 16, 32, 64,248), {#242}
- ( 16, 32, 64, 32, 16,248), {#243}
- ( 16, 40, 32, 32, 32, 32), {#244}
- ( 32, 32, 32, 32,160, 64), {#245}
- ( 0, 32, 0,248, 0, 32), {#246}
- (104,144, 0,104,144, 0), {#247}
- ( 96,144, 96, 0, 0, 0), {#248}
- ( 0, 0, 0, 48, 0, 0), {#249}
- ( 0, 0, 0, 16, 0, 0), {#250}
- ( 60, 32, 32,160, 96, 32), {#251}
- (176, 72, 72, 0, 0, 0), {#252}
- (224, 16, 96,128,240, 0), {#253}
- ( 0, 0,112,112, 0, 0), {#254}
- ( 0, 0, 0, 0, 0, 0));{#255}
-
- VAR Steigung:BYTE; {determines, which algorithm will be used }
- DY_mal2,DY_m_DX_mal2:INTEGER;
- oldMode:byte;
- regs:registers;
-
- IsAT:BYTE;
- TimeFlag:BYTE;
- CycleTime:LONGINT;
-
- CRTAddress, StatusReg : WORD;
-
-
- {-----------------------------------------------------}
-
- PROCEDURE ShadowTab; ASSEMBLER;
- {Pseudo-procedure to store the color lookup table into the code segment}
- {DO NOT TRY TO CALL THIS "PROCEDURE"!!! }
- {default values correspond to a darkening to 70% of the original brightness}
- ASM
- DB 254,104,120,124,112,108,114, 24, 20,128,144, 3,136, 5,140, 7
- DB 254,254, 17, 17, 18, 19, 20, 20, 21, 8, 23, 24, 24, 25, 26, 7
- DB 1, 1,107,108, 5,108,109, 4, 4, 4, 6, 6,116,116,117, 2
- DB 2, 2,123,124, 3,124,125, 1,152,155,156,156, 5,156,156,157
- DB 160,163,164,164,164,164,164,165,168,171,172,172, 3,172,172,173
- DB 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24
- DB 24, 24, 24, 24, 24, 24, 24, 24,176,177,178,179,180,181,182,183
- DB 184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199
- DB 200,201,203,204,204,204,205,207,208,209,211,212,212,212,213,215
- DB 216,217,219,220,220,220,221,223,246,227,228,228,228,228,228,229
- DB 234,235,236,236,236,236,236,237,242,243,244,244,244,244,244,245
- DB 254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254
- DB 254,254,254,254,254,254,254,254, 17, 17, 17, 17, 17, 17, 17, 17
- DB 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17
- DB 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17
- DB 17, 17, 17, 17, 17, 17, 17, 17,254,254,254,254,254,254,254, 7
- END;
-
- PROCEDURE CS_TranslateTab; ASSEMBLER;
- {Small pseudo-procedure to store lookup table for the bitmasks into }
- {the code segment, too}
- ASM
- DB 1,2,4,8
- END;
-
- PROCEDURE SetShadowTab(brightness:BYTE);
- { in: brightness = wanted brightness for the colors in the shadow area, }
- { in percentage of the brightness of the original colors }
- {out: ShadowTab = (best approximation) color table for wanted dimming }
- { Schatten = new brightness (Schatten is a global variable!) }
- {rem: default value of ShadowTab is 70% of the original color brightness! }
- { This routine takes some time (about 4 sec on a 8MHz-AT!) }
-
- VAR neue_Tabelle:ColorTable;
- p1:POINTER;
-
- BEGIN
- IF (brightness<0) OR (brightness>100)
- THEN BEGIN
- Error:=Err_InvalidPercentage;
- exit
- END;
- p1:=@neue_Tabelle; {trick, as the assembler messes up accesses to the SS-segment}
- ASM
- MOV CX,256 {outer loop-counter }
- LES DI,p1 {ES:DI=^neue_Tabelle[i] }
- MOV SI,OFFSET ActualColors {DS:SI=^ActualColors[]}
-
- @outerloop:
- LODSB {AL=tempColors[i].red}
- MUL brightness {will be addressed via SS! }
- MOV DL,100
- DIV DL {AL=tempColors[i].red*brightness DIV 100}
- MOV BL,AL {BL := AL = new red part }
-
- LODSB {dto., for green }
- MUL brightness
- MOV DL,100
- DIV DL
- MOV BH,AL {...into BH}
-
- LODSB {dto., for blue }
- MUL brightness
- MOV DL,100
- DIV DL
- MOV DH,AL {...into DH}
-
- {BL/BH/DH = RGB-parts of the color, for which we are seeking an approximation}
- PUSH CX
- PUSH SI
- PUSH DI
- PUSH BP
-
- MOV DI,65535 {min. square of error (up to now) }
- MOV CX,256 {walk through all 256 default colors}
- MOV SI,OFFSET ActualColors {DS:SI=^ActualColors[]}
- @searchloop:
- MOV AL,BL {compute difference in red part }
- SUB AL,[SI]
- JL @noNewMin {new color may not be brighter! }
- MUL AL {compute square of error}
- MOV BP,AX
-
- MOV AL,BH {dto., for green part }
- SUB AL,[SI+1]
- JL @noNewMin
- MUL AL
- ADD BP,AX
- JC @noNewMin {don't tolerate huge color differences }
-
- MOV AL,DH {dto., for blue part }
- SUB AL,[SI+2]
- JL @noNewMin
- MUL AL
- ADD AX,BP
- JC @noNewMin
-
- CMP AX,DI {did we find a better approximation?}
- JAE @noNewMin {no }
- MOV DI,AX {yes, store square of error and color}
- MOV DL,CL
- OR DI,DI {square of error = 0?}
- JZ @ColorDone {yes, we can't find any better solution than that! }
-
- @noNewMin:
- ADD SI,3
- LOOP @searchloop
-
- CMP DI,65535 {no color found? }
- JNE @ColorDone {but yes, nothing to do!}
- MOV CX,256 {no, thus search again }
- MOV SI,OFFSET ActualColors {DS:SI=^ActualColors[]}
- @searchloop2:
- LODSB
- SUB AL,BL {Diff ≈±2^6 -> square ≈±2^12 -> 3*square<MaxInt }
- IMUL AL {so no overflow is possible }
- MOV BP,AX
-
- LODSB {dto., for green part }
- SUB AL,BH
- IMUL AL
- ADD BP,AX
-
- LODSB {dto., for blue part }
- SUB AL,DH
- IMUL AL
- ADD AX,BP
-
- CMP AX,DI {did we find a better approximation?}
- JAE @noNewMin2 {no }
- MOV DI,AX {yes, store square of error and color}
- MOV DL,CL
-
- @noNewMin2:
- LOOP @searchloop2
-
-
- @ColorDone: {100h-DL = optimal color found }
- POP BP
- POP DI {ES:DI=^neue_Tabelle[i] }
- POP SI {DS:SI=^ActualColors[i] }
- POP CX
-
- MOV AL,DL {store into neue_Tabelle[i] }
- NEG AL {AL=100h-DL = best approximation}
- STOSB
-
- DEC CX {replacement for "LOOP @outerloop"; next color!}
- JCXZ @fertig
- JMP @outerloop
- @fertig:
-
- END; {of ASM}
- MOVE(neue_Tabelle,@ShadowTab^,256); {activate new color table}
- Schatten:=brightness
- END;
-
- PROCEDURE SetPalette(pal:Palette; update:BOOLEAN);
- { in: pal = pointer to palette to be set }
- { update = TRUE/FALSE for: recompute/don't recompute ShadowTab}
- {out: ActualColors = actual color palette }
- {rem: palette has been set and evtl., ShadowTab has been recomputed }
- BEGIN
- IF @pal<>@ActualColors
- THEN ActualColors:=pal; {copy palette into ActualColors }
- ASM
- MOV SI,OFFSET ActualColors {DS:SI=^ActualColors[]}
-
- CLI
-
- mov dx,StatusReg
- @WaitNotVSyncLoop:
- in al,dx
- and al,8
- jnz @WaitNotVSyncLoop
- @WaitVSyncLoop:
- in al,dx
- and al,8
- jz @WaitVSyncLoop
-
- MOV DX,3C8h
- XOR AL,AL
- OUT DX,AL
- INC DX
-
- MOV CX,256
- @L1:
- LODSB
- OUT DX,AL
- LODSB
- OUT DX,AL
- LODSB
- OUT DX,AL
- LOOP @L1
-
- STI
- END; {of ASM}
- IF update THEN SetShadowTab(Schatten)
- END;
-
- PROCEDURE GetPalette(VAR pal:Palette); ASSEMBLER;
- { in: pal = pointer to palette memory }
- {out: pal = actually set palette }
- ASM
- CLI
- XOR AL,AL
- MOV DX,3C7h
- OUT DX,AL
- LES DI,pal
- MOV CX,768
- MOV DX,3C9h
- @L1:
- IN AL,DX
- STOSB
- LOOP @L1
- STI
- END;
-
- FUNCTION LoadPalette(name:String; number:BYTE; VAR pal:Palette):WORD;
- { in: name = name of the palette file (type: "*.PAL") to load }
- { number = number for the first color being read in from the file }
- { ActualColors = actually set color palette }
- {out: number of colors read from the file (0 = an error occured) }
- { pal = color palette read from the file, evtl. filled up}
- {rem: All entries in "pal" which get not overwritten by the file's contents}
- { will become set to the actually set colors of "ActualColors"; the }
- { palette will only become loaded, not actually set!}
- LABEL quitloop;
- VAR len:LONGINT;
- f:File;
- i,count:WORD;
- TempPal:Palette;
- flag:BOOLEAN;
- BEGIN
- count:=0; {number of palette entries read in til now }
- assign(f,name);
- {$I-} reset(f,1); {$I+}
- if (ioresult<>0)
- THEN BEGIN {File doesn't exist or at least not with that path }
- Error:=Err_FileIO;
- LoadPalette:=0; exit
- END;
- len:=filesize(f); {determine file length}
- if (len mod 3<>0) OR (len>3*256) OR (len<3)
- THEN BEGIN
- Error:=Err_NoPalette;
- goto quitloop;
- END;
- IF len+number*3>3*256
- THEN BEGIN
- Error:=Err_PaletteWontFit;
- goto quitloop;
- END;
-
- TempPal:=ActualColors; {preset temporary palette with actual colors }
- {$I-}
- blockread(f,TempPal[number],len);
- {$I+}
-
- IF (ioresult<>0)
- THEN BEGIN
- Error:=Err_FileIO;
- goto quitloop;
- END;
-
- flag:=FALSE;
- FOR i:=number TO Pred(number+(len DIV 3))
- DO flag:=flag OR (TempPal[i].red>63)
- OR (TempPal[i].green>63)
- OR (TempPal[i].blue>63);
- IF flag
- THEN BEGIN
- Error:=Err_NoPalette;
- goto quitloop;
- END;
-
- {everything went alright: return palette}
- pal:=TempPal;
- count:=len DIV 3;
-
- quitloop: ;
- close(f);
- LoadPalette:=count
- END;
-
- {Now, all the code pieces follow, which can be used to display a sprite; }
- {the interface used is the same for all of them: }
- { in: CX = number of bytes, which have to be copied from... }
- { DS:SI = (pointer to source address) to... }
- { ES:BX = (pointer to destination address) }
- { DI = bitplane (0..3) (=X-coordinate AND 3) }
- { The proper bitmask for selecting the correct write plane has al- }
- { ready been set, but not that for the evtl. needed read plane! }
- { The routines can rely upon CX being <>0 }
- {rem: Every routine MUST CONSIST OF EXACTLY 16 bytes and BE FULLY RELO- }
- { CATIBLE and MAY NOT CHANGE registers BP,DS and ES!!!!!!!!!!!!!!!!! }
- { Besides that, for distinguishtability, the routines must be pair- }
- { wise disjoint in their first two bytes! }
-
- PROCEDURE Modus0; ASSEMBLER;
- {mode 0 considers color 0 being transparent for background data }
- ASM
- INC CX
- STC {change BX such that (together with SI) it can be }
- SBB BX,SI {used for accessing the target address}
- @L1:
- LODSB {fetch sprite byte }
- OR AL,AL {is it zero? }
- LOOPZ @L1 {yes, ignore it }
- JCXZ @L2 {all bytes done? }
- MOV ES:[BX+SI],AL {no, store to screen}
- JMP @L1 {short} {work on next byte }
- @L2:
- END;
-
- PROCEDURE Modus1; ASSEMBLER;
- {mode 1 writes the data directly to the screen, without further processing }
- ASM
- MOV DI,BX {set DI so that the string instructions can be used }
- XOR AX,AX {set AX:=0 }
- SHR CX,1 {number of words to move }
- REP MOVSW {move data as one block at once }
- ADC CX,AX {does a single byte remain? }
- REP MOVSB
- MOV AX,AX {4 filling bytes; faster than 4 NOPs}
- MOV AX,AX
- END;
-
- PROCEDURE Modus2Work; ASSEMBLER;
- {Continuation of mode2 - everything, which didn't fit in the reserved 16 }
- {bytes is placed here}
- ASM
- OUT DX,AX {enable read access for correct plane }
-
- PUSH DS {DS still points to sprite data, but must }
- {point to background! }
- MOV AX,ES {DS:SI := ES:DI (source ptr:=dest. ptr) }
- MOV DS,AX
- MOV SI,DI
- MOV BX,OFFSET ShadowTab {set pointer to color lookup table }
-
- @L4:
- LODSB {get background color... }
- SEGCS XLAT {...use color lookup table to transform}
- STOSB {...and display on actual graphic page}
- LOOP @L4
-
- POP DS
- END;
-
- PROCEDURE Modus2; ASSEMBLER;
- {mode 2 is thought for "shadows" and the like: the sprite's data itself }
- {will be ignored; instead, the background data underneath the sprite's }
- {position is read in and these color values will be exchanged against }
- {those of the color lookup table "ShadowTab" (e.g.: to realize shadows, }
- {this table should hold a darker color for each of the original colors) }
- ASM
- MOV AX,DI {bring bitplane for read access to AX }
- MOV DI,BX {put dest. addr. into DI for 8086's string instructions}
- MOV AH,AL {bring bitplane to highbyte }
- MOV AL,4
- MOV DX,3CEh
- MOV SI,OFFSET Modus2Work {sort of hack: "CALL Modus2Work" would be coded}
- CALL SI {RELATIVE - and thus, jump to ever-neverland! }
- END;
-
- PROCEDURE Modus3Work; ASSEMBLER;
- {continuation of Modus3 - everything, which didn't fit into 16 bytes }
- {bytes is placed here}
- ASM
- STC
- SBB BX,SI {address source and destination with only 1 index register}
- MOV DX,BP {save BP-register }
- MOV BP,BX
- MOV BX,OFFSET ShadowTab {set pointer to color lookup table }
-
- @L1:
- LODSB {get sprite data... }
- OR AL,AL { (ignore color 0 as "transparent") }
- LOOPZ @L1
- JCXZ @L2
- MOV AL,ES:[BP+SI] {get background color... }
- SEGCS XLAT {...use color lookup table to transform}
- MOV ES:[BP+SI],AL {...and display on actual graphic page}
- JMP @L1
- @L2:
- MOV BP,DX {restore old contents of BP register }
- END;
-
- PROCEDURE Modus3; ASSEMBLER;
- {Modus3 is thought for "shadows", too: in this mode, all sprite }
- {pixels with color <>0 will be processed: the background color, which is }
- {underneath these pixels will be replaced by the corresponding color entry }
- {from the table "ShadowTab" }
- {In other words: this mode is equivalent to Modus2, with the exception }
- {that sprite color 0 is treated as being transparent for shadows }
- {too! }
- ASM
- MOV DX,3CEh {prepare access to read plane: }
- MOV AX,DI
- MOV AH,AL {load read plane into AH }
- MOV AL,4
- OUT DX,AX {enable read access for correct plane }
- INC CX {inc. number of bytes by 1 (-> LODSB!) }
- MOV AX,OFFSET Modus3Work {trick to make code relocatible! }
- CALL AX
- END;
-
- PROCEDURE Adressen; ASSEMBLER;
- {table with the starting addresses of the 3 routines in the code segment}
- ASM
- DW OFFSET Modus0
- DW OFFSET Modus1
- DW OFFSET Modus2
- DW OFFSET Modus3
- END;
-
-
- PROCEDURE GADR; ASSEMBLER;
- {table with graphic rows starting addresses (offset part)}
- ASM
- DW $0000,$0050,$00A0,$00F0,$0140,$0190,$01E0,$0230
- DW $0280,$02D0,$0320,$0370,$03C0,$0410,$0460,$04B0
- DW $0500,$0550,$05A0,$05F0,$0640,$0690,$06E0,$0730
- DW $0780,$07D0,$0820,$0870,$08C0,$0910,$0960,$09B0
- DW $0A00,$0A50,$0AA0,$0AF0,$0B40,$0B90,$0BE0,$0C30
- DW $0C80,$0CD0,$0D20,$0D70,$0DC0,$0E10,$0E60,$0EB0
- DW $0F00,$0F50,$0FA0,$0FF0,$1040,$1090,$10E0,$1130
- DW $1180,$11D0,$1220,$1270,$12C0,$1310,$1360,$13B0
- DW $1400,$1450,$14A0,$14F0,$1540,$1590,$15E0,$1630
- DW $1680,$16D0,$1720,$1770,$17C0,$1810,$1860,$18B0
- DW $1900,$1950,$19A0,$19F0,$1A40,$1A90,$1AE0,$1B30
- DW $1B80,$1BD0,$1C20,$1C70,$1CC0,$1D10,$1D60,$1DB0
- DW $1E00,$1E50,$1EA0,$1EF0,$1F40,$1F90,$1FE0,$2030
- DW $2080,$20D0,$2120,$2170,$21C0,$2210,$2260,$22B0
- DW $2300,$2350,$23A0,$23F0,$2440,$2490,$24E0,$2530
- DW $2580,$25D0,$2620,$2670,$26C0,$2710,$2760,$27B0
- DW $2800,$2850,$28A0,$28F0,$2940,$2990,$29E0,$2A30
- DW $2A80,$2AD0,$2B20,$2B70,$2BC0,$2C10,$2C60,$2CB0
- DW $2D00,$2D50,$2DA0,$2DF0,$2E40,$2E90,$2EE0,$2F30
- DW $2F80,$2FD0,$3020,$3070,$30C0,$3110,$3160,$31B0
- DW $3200,$3250,$32A0,$32F0,$3340,$3390,$33E0,$3430
- DW $3480,$34D0,$3520,$3570,$35C0,$3610,$3660,$36B0
- DW $3700,$3750,$37A0,$37F0,$3840,$3890,$38E0,$3930
- DW $3980,$39D0,$3A20,$3A70,$3AC0,$3B10,$3B60,$3BB0
- DW $3C00,$3C50,$3CA0,$3CF0,$3D40,$3D90,$3DE0,$3E30
- END;
-
-
- FUNCTION AT:BOOLEAN;
- { in: - }
- {out: TRUE/FALSE, if the machine is (at least) an AT }
- BEGIN
- AT:=MEM[$F000:$FFFE]=$FC
- END;
-
-
- PROCEDURE SetCycleTime(milliseconds:WORD);
- { in: min. time for one animation cycle in milliseconds }
- {out: CycleTime := that value in microseconds }
- { TimeFlag := $80}
- {rem: Because of TimeFlag:=$80, the timing mechanism won't work }
- { for the very first animation cycle, yet! }
- { If you don't use the timing mechanism (by supplying a value}
- { of 0 milliseconds), this will result in IsAT:=$80, that is }
- { the routine will fake "computer is a PC". Else IsAT=0 }
- BEGIN
- TimeFlag:=$80;
- CycleTime:=LONGINT(milliseconds)*LONGINT(1000);
- IF (milliseconds<>0) AND AT
- THEN IsAT:=0 {yes, time control mechanism shall be used }
- ELSE IsAT:=$80 {no, none possible or not wanted }
- END;
-
- PROCEDURE SetSpriteCycle(nr,len:WORD);
- { in: nr = spriteloadnumber of the first sprite in the cycle }
- { len = length of your sprite cycle }
- {out: NextSprite[nr] through NextSprite[nr+len-1] have been set }
- { set such that they build a "ring", that is: together }
- { they make up a sprite cycle}
- {rem: If the sprite cycle shall consist of (physical) sprites }
- { whose load numbers aren't consecutive, then you }
- { have to make the appropriate entries into NextSprite[] }
- { yourself manually }
- { This routine uses spriteLOADnumbers! }
- VAR i:WORD;
- BEGIN
- IF (nr<1) OR (nr+len-1>LoadMAX)
- THEN Error:=Err_InvalidSpriteLoadNumber
- ELSE BEGIN
- FOR i:=nr TO nr+len-2 DO NextSprite[i]:=SUCC(i);
- NextSprite[PRED(nr+len)]:=nr {last sprite points to first one}
- END;
- END;
-
-
- FUNCTION GetImage(x1,y1,x2,y2:INTEGER; pa:BYTE):POINTER;
- { in: (x1,y1) = upper left corner of the area which shall be stored }
- { (x2,y2) = according lower right corner (in virtual coordinates!) }
- { pa = graphic page from which the image should be taken (0..2) }
- { StartVirtualX,StartVirtualY = upper left image corner }
- {out: pointer to heap address where the copied screen area is stored }
- { left_cut= evtl. needed left cut off of the image (this determines, }
- { how many pixels at the left edge of the image lie outside }
- { of the screen) }
- { right_cut,top_cut,bottom_cut = dto., for the other boundaries }
- { was_cut = TRUE/FALSE, if it was necessary/not necessary to clip the }
- { fetched image }
- {rem: The memory needed will be reserved by the routine automatically }
- { If that is impossible (or the image is completely offscreen), the }
- { routine will return NIL! }
- { Only if "was_cut" is set to TRUE, the (global) "..._cut" variables }
- { will be set to something other then 0, that is: if the window lies }
- { _completely_ offscreen (this means: returned ptr=NIL), then the }
- { routine still returns "was_cut"=FALSE!}
- VAR len,breite,hoehe,StartAdr,actualAdr,SegmAdr:WORD;
- p:POINTER;
- BEGIN
- was_cut:=FALSE; left_cut:=0; right_cut:=0; top_cut:=0; bottom_cut:=0;
- dec(x1,StartVirtualX); {compute screen coordinates }
- dec(y1,StartVirtualY);
- IF (x1>XMAX) or (y1>YMAX) or (x2<0) or (y2<0) or (x1>x2) or (y1>y2)
- THEN BEGIN {window is offscreen }
- GetImage:=NIL;
- exit
- END;
- {cut clipping according to visible screen:}
- IF x1<0 THEN BEGIN left_cut :=-x1; x1:=0; was_cut:=TRUE END;
- IF y1<0 THEN BEGIN top_cut:=-y1; y1:=0; was_cut:=TRUE END;
- IF x2>XMAX THEN BEGIN right_cut :=x2-XMAX; x2:=XMAX; was_cut:=TRUE END;
- IF y2>YMAX THEN BEGIN bottom_cut:=y2-YMAX; y2:=YMAX; was_cut:=TRUE END;
-
- breite:=SUCC(x2-x1); hoehe:=SUCC(y2-y1);
- len:=breite*hoehe+2*2; {1 pixel=1 byte; add 2 words for width & height }
- IF len>MaxAvail
- THEN BEGIN
- Error:=Err_NotEnoughMemory;
- GetImage:=NIL;
- exit
- END;
- IF (pa<>0) AND (pa<>1) AND (pa<>BACKGNDPAGE) {page number must be 0..2 }
- THEN BEGIN
- Error:=Err_InvalidPageNumber;
- GetImage:=NIL;
- exit
- END
- ELSE SegmAdr:=Segment_Adr[pa];
- GetMem(p,len); {get memory from the heap }
- ASM
- CLD
- LES DI,p {ES:DI = pointer to the acquired memory }
- MOV AX,breite
- STOSW {store width first... }
- MOV AX,hoehe
- STOSW {...then store height, followed by the data }
-
- MOV BX,AX {BX:=height (to be used later) }
- MOV SI,y1
- SHL SI,1
- MOV SI,CS:[OFFSET gadr + SI] {SI:=y1*LINESIZE}
- MOV AX,x1
- MOV DL,AL
- SHR AX,1
- SHR AX,1
- ADD SI,AX {SI:=offset part of the start address}
- MOV StartAdr,SI
- MOV actualAdr,SI
- AND DL,3
- MOV AH,DL
- MOV AL,4
- MOV DX,3CEh
- OUT DX,AX {select start plane }
- MOV DS,SegmAdr
-
- {DS:SI = pointer to first byte to store; ES:DI = its target address }
- {AH = startplane, AL = 4, BX = number of rows to process }
-
- MOV DX,breite
- ADD DX,3
- SHR DX,1
- SHR DX,1 {DX = number of bytes to store for each row}
-
- @L1:
- MOV CX,DX {store data of one row }
- SHR CX,1 {faster than "REP MOVSB" }
- REP MOVSW
- ADC CX,0
- REP MOVSB
- MOV SI,actualAdr {increment source pointer by 1 graphic row}
- ADD SI,LINESIZE
- MOV actualAdr,SI
- DEC BX {decrease row counter }
- JNE @L1
-
- INC AH {select next plane }
- CMP AH,4
- JNE @nowrap1 {wrapping the bitplane means: start address }
- MOV AH,0 {needs mending: increment address by 1! }
- INC StartAdr
- @nowrap1:
- MOV DX,3CEh
- OUT DX,AX
- MOV BX,hoehe
- MOV DX,breite
- INC DX
- INC DX
- SHR DX,1
- SHR DX,1
- MOV SI,StartAdr
- MOV actualAdr,SI
-
- @L2:
- MOV CX,DX
- SHR CX,1 {faster than "REP MOVSB" }
- REP MOVSW
- ADC CX,0
- REP MOVSB
- MOV SI,actualAdr
- ADD SI,LINESIZE
- MOV actualAdr,SI
- DEC BX
- JNE @L2
-
- INC AH
- CMP AH,4
- JNE @nowrap2
- MOV AH,0
- INC StartAdr
- @nowrap2:
- MOV DX,3CEh
- OUT DX,AX
- MOV BX,hoehe
- MOV DX,breite
- INC DX
- SHR DX,1
- SHR DX,1
- MOV SI,StartAdr
- MOV actualAdr,SI
-
- @L3:
- MOV CX,DX
- SHR CX,1 {faster than "REP MOVSB" }
- REP MOVSW
- ADC CX,0
- REP MOVSB
- MOV SI,actualAdr
- ADD SI,LINESIZE
- MOV actualAdr,SI
- DEC BX
- JNE @L3
-
- INC AH
- CMP AH,4
- JNE @nowrap3
- MOV AH,0
- INC StartAdr
- @nowrap3:
- MOV DX,3CEh
- OUT DX,AX
- MOV BX,hoehe
- MOV DX,breite
- SHR DX,1
- SHR DX,1
- MOV SI,StartAdr
- MOV actualAdr,SI
-
- @L4:
- MOV CX,DX
- SHR CX,1 {faster than "REP MOVSB" }
- REP MOVSW
- ADC CX,0
- REP MOVSB
- MOV SI,actualAdr
- ADD SI,LINESIZE
- MOV actualAdr,SI
- DEC BX
- JNE @L4
-
- MOV AX,SEG @DATA
- MOV DS,AX
- END;
- GetImage:=p
- END;
-
- PROCEDURE PutImage(x,y:INTEGER; p:POINTER; pa:BYTE);
- { in: (x,y) = upper left corner of destination (virtual coordinates) }
- { p = pointer to the cutting (returned by GetImage) }
- { pa = graphic page to which the cutting shall be pasted to }
- { StartVirtualX,StartVirtualY = upper left image corner }
- {out: - }
- {rem: The cutting has been properly clipped before being displayed }
- { If you supply NIL as pointer, the routine will display nothing }
- { That is useful when you are going to use the routine directly on }
- { the results supplied by GetImage! }
- VAR breite,hoehe,SegmAdr,actualAdr,StartAdr,breite1,breite2,breite3,breite4,
- licut_div4,topcut,pl_adr1,pl_adr2,pl_adr3,pl_adr4:WORD;
- licutoff,temp:INTEGER;
- BEGIN
- IF p=NIL THEN exit;
- dec(x,StartVirtualX); {compute screen coordinates }
- dec(y,StartVirtualY);
- IF (x>XMAX) or (y>YMAX) THEN exit;
- IF (pa<>0) AND (pa<>1) AND (pa<>BACKGNDPAGE)
- THEN BEGIN
- Error:=Err_InvalidPageNumber;
- exit
- END
- ELSE SegmAdr:=Segment_Adr[pa];
- breite:=MEMW[SEG(p^):OFS(p^)];
- hoehe :=MEMW[SEG(p^):OFS(p^)+2];
- IF (x+breite<=0) or (y+hoehe<=0) THEN exit;
- IF x<0 THEN BEGIN licutoff:=-x; x:=0 END
- ELSE licutoff:=0;
- IF y<0 THEN BEGIN
- topcut:=-y;
- y:=0
- END
- ELSE topcut:=0;
-
- breite1:=(breite + 3) shr 2; {Width of a row for the first, second, }
- breite2:=(breite + 2) shr 2; {third and fourth bitplane, respectively}
- breite3:=(breite + 1) shr 2;
- breite4:=(breite + 0) shr 2;
-
- {Compute starting addresses of the 4 bitplanes; take into account evtl. }
- {left cutoff (+4 bytes to jump over "breite" (width) and "hoehe" (height) }
- licut_div4:=licutoff shr 2;
- pl_adr1:=4 +licut_div4 +topcut*breite1;
- pl_adr2:=4 +licut_div4 +topcut*breite2 +hoehe*breite1;
- pl_adr3:=4 +licut_div4 +topcut*breite3 +hoehe*(breite1+breite2);
- pl_adr4:=4 +licut_div4 +topcut*breite4 +hoehe*(breite1+breite2+breite3);
-
- {licutoff mod 4 determines the order in which the points must be read }
- {of the heap: 0 = plane order (1,2,3,4); 1 = plane order (2,3,4,1); }
- {2=(3,4,1,2); 3=(4,1,2,3); note that the widths of the bitplane tables }
- {are (and remain) linked to these; therefore, they will be swapped too }
- {to accomplish that! }
- ASM
- CLD
- MOV AX,licutoff
- AND AL,3
- OR AL,AL
- JE @no_exchange
- CMP AL,1
- JNE @L10
-
- MOV AX,pl_adr2 {displacement of 1 bit: }
- MOV BX,pl_adr3 {AX=Plane2,BX=Plane3,CX=Plane4,DX=Plane1}
- MOV CX,pl_adr4
- MOV DX,pl_adr1 {wrap-around, thus: increment address by 1, which }
- INC DX {corresponds to an ajustment of 4 points }
- MOV pl_adr1,AX {(e.g.: pixels (1,5,9,...),(2,6,10,...),(3,7,11,...)}
- MOV pl_adr2,BX {and (0,4,8,...); the last bitplane needs a cor- }
- MOV pl_adr3,CX {rection of +1 byte: this results in (4,8,12,...) }
- MOV pl_adr4,DX {(read planes top-down, in alternating order!) }
- MOV AX,breite2 {Now the plane widths: }
- MOV BX,breite3 {AX=Plane2,BX=Plane3,CX=Plane4,DX=Plane1}
- MOV CX,breite4
- MOV DX,breite1
- JMP @store
-
- @L10:
- CMP AL,2
- JNE @L20
-
- MOV AX,pl_adr3 {displacement of 2 bit: }
- MOV BX,pl_adr4 {AX=Plane3,BX=Plane4,CX=Plane1,DX=Plane2}
- MOV CX,pl_adr1
- INC CX
- MOV DX,pl_adr2
- INC DX
- MOV pl_adr1,AX
- MOV pl_adr2,BX
- MOV pl_adr3,CX
- MOV pl_adr4,DX
- MOV AX,breite3 {dto. for plane widths: }
- MOV BX,breite4 {AX=Plane3,BX=Plane4,CX=Plane1,DX=Plane2}
- MOV CX,breite1
- MOV DX,breite2
- JMP @store
- @L20:
- MOV AX,pl_adr4 {displacement of 3 bit: }
- MOV BX,pl_adr1 {AX=Plane4,BX=Plane1,CX=Plane2,DX=Plane3}
- INC BX
- MOV CX,pl_adr2
- INC CX
- MOV DX,pl_adr3
- INC DX
- MOV pl_adr1,AX
- MOV pl_adr2,BX
- MOV pl_adr3,CX
- MOV pl_adr4,DX
- MOV AX,breite4 {dto. for plane widths: }
- MOV BX,breite1 {AX=Plane4,BX=Plane1,CX=Plane2,DX=Plane3}
- MOV CX,breite2
- MOV DX,breite3
- @store:
- MOV breite1,AX
- MOV breite2,BX
- MOV breite3,CX
- MOV breite4,DX
-
- @no_exchange: {precondition here: (pl_adr?,breite?) contain the }
- {source bitplanes/-widths in the correct order }
-
- MOV AX,topcut
- SUB hoehe,AX {evtl. adjust height for upper cutoff }
- MOV AX,licutoff
- SUB breite,AX {dto. for width and left cutoff }
-
- MOV AX,x {if image would spread over the right screen }
- ADD AX,breite {boundary: compute right cutoff }
- SUB AX,XMAX+1
- JLE @no_recutoff
- SUB breite,AX {cut off AX points at the right}
- @no_recutoff:
-
- MOV AX,y {exactly the same for the lower screen border}
- ADD AX,hoehe
- SUB AX,YMAX+1
- JLE @no_bocutoff
- SUB hoehe,AX {cut off AX rows at the bottom}
- @no_bocutoff:
-
-
- LDS SI,p
- ADD pl_adr2,SI {add pointer's offset part to the plane address }
- ADD pl_adr3,SI
- ADD pl_adr4,SI
-
- ADD SI,pl_adr1 {width,height and parts above the screen }
- MOV ES,SegmAdr
-
- MOV DI,y
- SHL DI,1
- MOV DI,CS:[OFFSET gadr + DI] {DI:=y*LINESIZE}
- MOV AX,x
- MOV BL,AL
- SHR AX,1
- SHR AX,1
- ADD DI,AX {DI:=y*LINESIZE +(x DIV 4)}
- MOV StartAdr,DI
- MOV actualAdr,DI
-
- AND BX,3 {startplane:=x mod 3}
- MOV AH,CS:[OFFSET CS_TranslateTab + BX]
- MOV AL,2
- MOV DX,3C4h
- OUT DX,AX {use it as write plane }
-
- MOV DX,hoehe
- MOV DI,actualAdr
-
- {DS:SI = pointer to data, ES:DI = dest. address on screen for them }
- {AH = bitmask for access, AL = 2 }
- MOV BX,breite
- ADD BX,3
- SHR BX,1
- SHR BX,1
- mov cx,bx
- @L1:
- push si
- SHR CX,1 {faster than "REP MOVSB" }
- REP MOVSW
- ADC CX,0
- REP MOVSB
- pop si
- mov cx,bx
- add si,breite1
- MOV DI,actualAdr
- ADD DI,LINESIZE
- MOV actualAdr,DI
- DEC DX
- JNE @L1
-
-
- SHL AH,1 {select next bitplane; if wrap-around occurs }
- CMP AH,16 {from bitplane 3 to bitplane 0, then the start- }
- JNE @nowrap1 {ing address must be incremented by 1 byte }
- MOV AH,1
- INC StartAdr
- @nowrap1:
- MOV DX,3C4h
- OUT DX,AX
- MOV SI,pl_adr2
- MOV DI,StartAdr
- MOV actualAdr,DI
- MOV DX,hoehe
- MOV BX,breite
- INC BX
- INC BX
- SHR BX,1
- SHR BX,1
- mov cx,bx
- @L2:
- push si
- SHR CX,1 {faster than "REP MOVSB" }
- REP MOVSW
- ADC CX,0
- REP MOVSB
- pop si
- mov cx,bx
- add si,breite2
- MOV DI,actualAdr
- ADD DI,LINESIZE
- MOV actualAdr,DI
- DEC DX
- JNE @L2
-
-
- SHL AH,1
- CMP AH,16
- JNE @nowrap2
- MOV AH,1
- INC StartAdr
- @nowrap2:
- MOV DX,3C4h
- OUT DX,AX
- MOV SI,pl_adr3
- MOV DI,StartAdr
- MOV actualAdr,DI
- MOV DX,hoehe
- MOV BX,breite
- INC BX
- SHR BX,1
- SHR BX,1
- mov cx,bx
- @L3:
- push si
- SHR CX,1 {faster than "REP MOVSB" }
- REP MOVSW
- ADC CX,0
- REP MOVSB
- pop si
- mov cx,bx
- add si,breite3
- MOV DI,actualAdr
- ADD DI,LINESIZE
- MOV actualAdr,DI
- DEC DX
- JNE @L3
-
-
- SHL AH,1
- CMP AH,16
- JNE @nowrap3
- MOV AH,1
- INC StartAdr
- @nowrap3:
- MOV DX,3C4h
- OUT DX,AX
- MOV SI,pl_adr4
- MOV DI,StartAdr
- MOV actualAdr,DI
- MOV DX,hoehe
- MOV BX,breite
- SHR BX,1
- SHR BX,1
- mov cx,bx
- @L4:
- push si
- SHR CX,1 {faster than "REP MOVSB" }
- REP MOVSW
- ADC CX,0
- REP MOVSB
- pop si
- mov cx,bx
- add si,breite4
- MOV DI,actualAdr
- ADD DI,LINESIZE
- MOV actualAdr,DI
- DEC DX
- JNE @L4
-
- MOV AX,SEG @DATA
- MOV DS,AX
- END;
-
- END;
-
- PROCEDURE FreeImageMem(p:POINTER);
- { in: p = pointer to image memory, allocated by GetImage()}
- {out: - }
- {rem: the heap memory allocated for the image has been released }
- BEGIN
- IF p<>NIL THEN FreeMem(p,MEMW[Seg(p^):Ofs(p^)]*MEMW[Seg(p^):Ofs(p^)+2] + 2*2)
- END;
-
- PROCEDURE Screen(pa:BYTE);
- { in: pa = graphic page to be shown (0..3) }
- {out: - }
- {rem: The display has been switched to graphic page pa }
- { The routine does NOT synchronize on any retrace-signal }
- { Sensible page values are only 0 or 1 here, but the routine }
- { doesn't make any checks!}
- BEGIN
- ASM
- MOV DX,CRTAddress {CRT-Controller}
- MOV AL,$0D {LB-startaddress-register}
- CLI {May not be interrupted! }
- OUT DX,AL
- INC DX
- {realize "AX:=Offset_Adr[pa]": }
- MOV BL,pa
- MOV SI,BX
- AND SI,3 {page value *2 (word-sized entries!)}
- SHL SI,1 {add start address of array to that }
- ADD SI,OFFSET Offset_Adr-StartIndex*2 {evtl. correct displacement }
- LODSW {and fetch value}
- OUT DX,AL {set LB of new starting address }
- DEC DX
- MOV AL,$0C
- OUT DX,AL
- INC DX
- MOV AL,AH {set HB of new starting address }
- OUT DX,AL
- STI
- END;
- END;
-
- PROCEDURE InitGraph;
- { in: PAGE = actual graphic page }
- {out: - }
- {rem: switches the VGA-card into 320x200x256x4-mode; ATTENTION! }
- { This mode is different from mode $13 of the VGA-BIOS!!! }
- { The display will be switched to graphic page 1-PAGE }
- { The default colors of mode $13 will be set! }
- BEGIN
- ASM
- MOV AX,0013h {use BIOS to set graphic mode $13 (320x200x256) }
- INT 10h
- MOV DX,03C4h {select memory-mode-register at sequencer port }
- MOV AL,04
- OUT DX,AL
- INC DX {read in data via the according data register }
- IN AL,DX
- AND AL,0F7h {bit 3:=0 -> don't chain planes }
- OR AL,04 {bit 2:=1 -> no odd/even-scheme }
- OUT DX,AL {activate new settings }
- MOV DX,03C4h {s.a.: address sequencer reg. 2 (=map-mask),... }
- MOV AL,02
- OUT DX,AL
- INC DX
- MOV AL,0Fh {...and allow access to all 4 bit maps }
- OUT DX,AL
- MOV AX,0A000h {starting in segment A000h, set 8000h logical }
- MOV ES,AX {words = 4*8000h physical words (because of 4 }
- SUB DI,DI {bitplanes) to 0 }
- MOV AX,DI
- MOV CX,8000h
- CLD
- REP STOSW
-
- MOV DX,CRTAddress {address the underline-location-register at }
- MOV AL,14h {the CRT-controller port, read out the according }
- OUT DX,AL {data register: }
- INC DX
- IN AL,DX
- AND AL,0BFh {bit 6:=0 -> no double word addressing scheme in }
- OUT DX,AL {video ram }
- DEC DX
- MOV AL,17h {select mode control register }
- OUT DX,AL
- INC DX
- IN AL,DX
- OR AL,40h {bit 6:=1 -> address memory as a linear bit array }
- OUT DX,AL
- END;
- Screen(1-PAGE); {ALWAYS is the non-actual graphic page the visible one!}
- SetPalette(DefaultColors,FALSE) {set default palette, just to be sure! }
- END;
-
-
- PROCEDURE Line(x1,y1,x2,y2:INTEGER; pa:BYTE);
- { in: x1,y1,x2,y2 = coordinates of two points, }
- { Color = color (0..255) }
- { StartVirtualX,StartVirtualY = upper left image corner }
- { pa = graphic page to be drawn upon (0..2) }
- {out: - }
- {rem: A line has been drawn between the VIRTUAL points (x1,y1) and (x2,y2) }
- { using the color COLOR; the routine will take care of transforming }
- { the coordinates to absolute screen coordinates and evtl. necessary }
- { clipping actions. }
- { The line will NOT automatically be taken over into the background }
- { image, that is: it will be visible only for one animation cycle (if }
- { it shall stay permanent, you have to draw it into the background!) }
- { (For that reason, you should call this routine AFTER calling ANIMATE }
- { because otherwise, the drawn line will vanish at once!) }
- CONST CodeLinks =$7; {%0111}
- CodeRechts=$B; {%1011}
- CodeOben =$D; {%1101}
- CodeUnten =$E; {%1110}
- BEGIN
- IF (pa<>0) AND (pa<>1) AND (pa<>BACKGNDPAGE)
- THEN Error:=Err_InvalidPageNumber
- ELSE
- {first clip line to visible window; use Sutherland-Cohen-algorithm: }
- {use 4 bit-codes for: left|right|top|bottom }
- ASM
- CLD
- MOV CL,$F {start with %1111 }
- MOV AX,x2
- SUB AX,StartVirtualX {transform x2 into absolue coordinates}
- MOV x2,AX
- OR AX,AX {x2<0 ?}
- JL @GC1Punkt2 {yes, don't change flag for "point is left of window"}
- AND CL,CodeLinks {no, reset flag }
- @GC1Punkt2:
- CMP AX,XMAX {x2>XMAX ?}
- JG @GC2Punkt2 {yes, don't change flag for "point is right of window"}
- AND CL,CodeRechts {no, reset flag }
- @GC2Punkt2:
- MOV AX,y2
- SUB AX,StartVirtualY {transform y2 into absolue coordinates}
- MOV y2,AX
- OR AX,AX {y2<0 ?}
- JL @GC3Punkt2 {yes, don't change flag for "point is above window"}
- AND CL,CodeOben {no, reset flag }
- @GC3Punkt2:
- CMP AX,YMAX {y2>YMAX ?}
- JG @GC4Punkt2 {yes, don't change flag for "point is below window"}
- AND CL,CodeUnten
- @GC4Punkt2: {CL holds the area code for point 2 }
-
- MOV AX,x1
- SUB AX,StartVirtualX {transform x1 into absolue coordinates}
- MOV x1,AX
- MOV AX,y1
- SUB AX,StartVirtualY {transform y1 into absolue coordinates}
- MOV y1,AX
-
- @Punkt1:
- MOV CH,$F {start with %1111 }
- MOV AX,x1
- OR AX,AX {x1<0 ?}
- JL @GC1Punkt1 {yes, don't change flag for "point is left of window"}
- AND CH,CodeLinks {no, reset flag }
- @GC1Punkt1:
- CMP AX,XMAX {x1>XMAX ?}
- JG @GC2Punkt1 {yes, don't change flag for "point is right of window"}
- AND CH,CodeRechts {no, reset flag }
- @GC2Punkt1:
- MOV AX,y1
- OR AX,AX {y1<0 ?}
- JL @GC3Punkt1 {yes, don't change flag for "point is above window"}
- AND CH,CodeOben {no, reset flag }
- @GC3Punkt1:
- CMP AX,YMAX {y1>YMAX ?}
- JG @GC4Punkt1 {yes, don't change flag for "point is below window"}
- AND CH,CodeUnten
- @GC4Punkt1: {CH holds the area code for point 1 }
-
- {CL holds the area code for point 2, CH the one for point 1 }
-
- MOV AX,CX
- AND AL,AH {Code1 AND Code2 <>0 ?}
- JNZ @LineReady {yes, line is completely outside the window}
- MOV AX,CX
- OR AL,AH {Code1 OR Code2 =0 ?}
- JZ @DrawLine {yes, line is completely inside the window}
-
- {Now do the clipping itself: }
- MOV AX,CX
- OR AH,AH {Code1 =0 ?}
- JNZ @CL3 {no, everything ok}
- MOV AX,x1 {yes, swap points! }
- XCHG AX,x2
- MOV x1,AX
- MOV AX,y1
- XCHG AX,y2
- MOV y1,AX
- XCHG CL,CH
- @CL3:
- MOV AL,CH {AL:=Code1}
- MOV BX,x2
- SUB BX,x1 {BX:=x2-x1}
- MOV SI,y2
- SUB SI,y1 {SI:=y2-y1}
- TEST AL,NOT CodeLinks {point1 left of window? }
- JZ @CL4 {no }
- {yes, compute new coordinates: y1:=y1+(y2-y1)/(x2-x1)*(WindowX1-X1) }
- {and x1:=WindowX1 (here, WindowX1 = 0) }
- XOR AX,AX
- XCHG AX,x1 {x1:=0}
- NEG AX {AX:=-x1old}
- IMUL SI
- IDIV BX
- ADD y1,AX
- JMP @Punkt1
-
- @CL4:
- TEST AL,NOT CodeRechts {point1 right of window? }
- JZ @CL5 {no }
- {yes, compute y1:=y1+(y2-y1)/(x2-x1)*(WindowX2-X1), x1:=WindowX2 }
- { (here, WindowX2=XMAX) }
- MOV AX,XMAX
- SUB AX,x1
- IMUL SI
- IDIV BX
- ADD y1,AX
- MOV x1,XMAX
- JMP @Punkt1
-
- @CL5:
- TEST AL,NOT CodeOben {point1 above window? }
- JZ @CL6 {no }
- {yes, compute x1:=x1+(x2-x1)/(y2-y1)*(WindowY1-y1), y1:=WindowY1 }
- { (here, WindowY1=0) }
- XOR AX,AX
- XCHG AX,y1
- NEG AX
- IMUL BX
- IDIV SI
- ADD x1,AX
- JMP @Punkt1
-
- @CL6:
- TEST AL,NOT CodeUnten {point below window? }
- JZ @Punkt1 {no }
- {yes, compute x1:=x1+(x2-x1)/(y2-y1)*(WindowY2-y1), y1:=WindowY2 }
- { (here, WindowY2=YMAX) }
- MOV AX,YMAX
- SUB AX,y1
- IMUL BX
- IDIV SI
- ADD x1,AX
- MOV y1,YMAX
- JMP @Punkt1
-
- {precondition here: both points have been clipped to the visible window;}
- {if the line is completely offscreen, the program jumped directly to }
- {@LineReady, instead! }
- @DrawLine:
- PUSH BP
- MOV Steigung,0 {reset Flag }
- MOV CX,x2
- SUB CX,x1 {point1 right of point2 ? }
- JGE @posDX {no }
- NEG CX {yes, swap points }
- MOV AX,x1
- XCHG AX,x2
- MOV x1,AX
- MOV AX,y1
- XCHG AX,y2
- MOV y1,AX
-
- @posDX:
- MOV DI,y1
- SHL DI,1
- MOV DI,CS:[OFFSET gadr + DI] {DI:=y1*LINESIZE}
- MOV AX,x1
- MOV BL,AL
- SHR AX,1
- SHR AX,1
- ADD DI,AX {DI:=y1*LINESIZE+(x1 DIV 4) }
-
- AND BX,3 {BX:=(x1 AND 4) }
- MOV DH,[OFFSET TranslateTab + BX] {get mask for VRAM-access }
- MOV DL,2
-
- MOV BL,pa {BH=0 -> BX=drawing page}
- SHL BX,1
- ADD BX,OFFSET Segment_Adr -StartIndex*2
- MOV ES,[BX]
-
- {ES:DI=pointer to graphic address of point1, DX=access mask for it }
- MOV SI,LINESIZE
- MOV BX,y2
- SUB BX,y1 {point1 below point2 ? }
- JG @posDY {no }
- NEG BX {yes, negate deltaY and row-increment }
- NEG SI
-
- @posDY:
- CMP BX,CX {deltaY>deltaX ?}
- JLE @flach {no: small slope, <=1 }
- XCHG BX,CX {yes, swap deltas and set flag }
- MOV Steigung,1
-
- {compute Bresenham-parameters: 2*DY, 2*DY-DX, 2*(DY-DX) }
- @flach:
- SHL BX,1
- MOV DY_mal2,BX
- SUB BX,CX
- MOV BP,BX {BP:=2*DY-DX}
- SUB BX,CX
- MOV DY_m_DX_mal2,BX
- INC CX {CX:=number of pixels}
- MOV BL,Color
- MOV BH,1
- CMP Steigung,0 {steep line? }
- JNZ @high1 {yes}
-
- @low1: {no }
- MOV AX,3C4h
- XCHG AX,DX
- OUT DX,AX {select correct bitplane }
- MOV DX,AX {save mask to DX again }
- MOV AL,BL {get color of point }
- STOSB {draw point }
- SHL DH,1 {compute mask for next point }
- CMP DH,16 {still addressable with the same address? }
- JE @nextbyte1 {no, address had to be incremented by 1 }
- DEC DI {yes, make increase of DI undone }
- @low1b:
- OR BP,BP
- JGE @low2
- ADD BP,DY_mal2
- LOOP @low1
- JMP @raus
- @nextbyte1:
- MOV DH,BH {restore mask to 1 }
- JMP @low1b {rest as above }
-
- @low2:
- ADD BP,DY_m_DX_mal2
- ADD DI,SI
- LOOP @low1
- JMP @raus
-
-
- @high1:
- MOV AX,3C4h
- XCHG AX,DX
- OUT DX,AX
- MOV DX,AX
- MOV AL,BL
- @high1b:
- OR BP,BP
- JGE @high2
- ADD BP,DY_mal2
- MOV ES:[DI],AL
- ADD DI,SI
- LOOP @high1b
- JMP @raus
-
- @high2:
- ADD BP,DY_m_DX_mal2
- SHL DH,1
- CMP DH,16
- JE @nextbyte2
- MOV ES:[DI],AL
- ADD DI,SI
- LOOP @high1
- JMP @raus
- @nextbyte2:
- MOV DH,BH
- STOSB
- ADD DI,SI
- LOOP @high1
-
- @raus:
- POP BP
- @LineReady:
- END;
- END;
-
- PROCEDURE BackgroundLine(x1,y1,x2,y2:INTEGER);
- { in: x1,y1,x2,y2 = coordinates of two points, }
- { Color = color (0..255) }
- { StartVirtualX,StartVirtualY = upper left image corner }
- {out: - }
- {rem: A line has been drawn between the VIRTUAL points (x1,y1) and (x2,y2) }
- { (using the color COLOR) into the background page; the routine it- }
- { self takes care of coordinate transformations and evtl. necessary }
- { clipping actions. }
- { The line will NOT be visible until the next animation cycle takes }
- { place (but then, it stays permanent)! (For that reason, you normally}
- { will call this routine BEFORE calling ANIMATE, because this way, all }
- { changes will become visible (via ANIMATE) at once) }
- { Because BACKGNDADR is used as background page, calling this rou- }
- { tine only makes sense when using background mode STATIC! }
- BEGIN
- Line(x1,y1,x2,y2,BACKGNDPAGE)
- END;
-
- FUNCTION GetPixel(x,y:INTEGER):BYTE; ASSEMBLER;
- { in: x,y = VIRTUAL pixel coordinates of the point to be read }
- { PAGEADR= graphic page(segment) to be read from }
- { StartVirtualX, StartVirtualY = upper left image corner }
- {out: color of the point}
- {rem: If the pixel lies outside the visible window, the routine }
- { will return "0" as the result }
- { Attention! As PAGEADR always specifies the NOT visible gra- }
- { phic page, this routine will read from there, too! }
- ASM
- XOR AL,AL {preset AL with 0 }
- MOV DI,y
- SUB DI,StartVirtualY {transform y into absolue coordinates}
- JS @offscrn
- CMP DI,YMAX
- JG @offscrn
- MOV BX,x
- SUB BX,StartVirtualX {transform x into absolute coordinates}
- JS @offscrn
- CMP BX,XMAX
- JG @offscrn
- SHL DI,1
- MOV DI,CS:[OFFSET gadr + DI]
- {DI = Y*LINESIZE, BX = X, coordinates admissible}
- MOV AX,BX
- SHR AX,1
- SHR AX,1
- ADD DI,AX {DI = Y*LINESIZE+(X SHR 2) }
- AND BL,3 {BL = X MOD 4 = plane to read from}
- MOV AL,4
- MOV AH,BL
- MOV DX,3CEh
-
- MOV ES,PAGEADR
- CLI
- OUT DX,AX
- MOV AL,ES:[DI]
- STI
- @offscrn:
- END;
-
- FUNCTION BackgroundGetPixel(x,y:INTEGER):BYTE; ASSEMBLER;
- { in: x,y = VIRTUAL pixel coordinates of the point to be read }
- { StartVirtualX, StartVirtualY = upper left image corner }
- {out: color of the point in the background page}
- {rem: If the pixel lies outside the visible window, the routine }
- { will return "0" as the result }
- { Because BACKGNDADR is used as background page, calling }
- { this routine only makes sense when using mode STATIC! }
- ASM
- XOR AL,AL {preset AL with 0 }
- MOV DI,y
- SUB DI,StartVirtualY {transform y into absolue coordinates}
- JS @offscrn
- CMP DI,YMAX
- JG @offscrn
- MOV BX,x
- SUB BX,StartVirtualX {transform x into absolute coordinates}
- JS @offscrn
- CMP BX,XMAX
- JG @offscrn
- SHL DI,1
- MOV DI,CS:[OFFSET gadr + DI]
- {DI = Y*LINESIZE, BX = X, coordinates admissible}
- MOV AX,BX
- SHR AX,1
- SHR AX,1
- ADD DI,AX {DI = Y*LINESIZE+(X SHR 2) }
- AND BL,3 {BL = X MOD 4 = plane to read from}
- MOV AL,4
- MOV AH,BL
- MOV DX,3CEh
- MOV ES,BACKGNDADR
- CLI
- OUT DX,AX
- MOV AL,ES:[DI]
- STI
- @offscrn:
- END;
-
- FUNCTION PageGetPixel(x,y:INTEGER; pa:BYTE):BYTE; ASSEMBLER;
- { in: x,y = VIRTUAL pixel coordinates of the point to be read }
- { pa = graphic page (0..3), from which the point shall be }
- { read out }
- { StartVirtualX, StartVirtualY = upper left image corner }
- {out: color of the point in the background page}
- {rem: If the pixel lies outside the visible window, the routine }
- { will return "0" as the result }
- { If you want to read from the actually VISIBLE page, then }
- { then you must call the routine with pa=1-PAGE! }
- { Sensible values for "pa" are either 0 or 1 (and evtl. BACK- }
- { GNDPAGE, if you are using background mode STATIC), however, }
- { the routine doesn't check that! }
- ASM
- XOR AL,AL {preset AL with 0 }
- MOV DI,y
- SUB DI,StartVirtualY {transform y into absolue coordinates}
- JS @offscrn
- CMP DI,YMAX
- JG @offscrn
- MOV BX,x
- SUB BX,StartVirtualX {transform x into absolute coordinates}
- JS @offscrn
- CMP BX,XMAX
- JG @offscrn
- SHL DI,1
- MOV DI,CS:[OFFSET gadr + DI]
- {DI = Y*LINESIZE, BX = X, coordinates admissible}
- MOV AX,BX
- SHR AX,1
- SHR AX,1
- ADD DI,AX {DI = Y*LINESIZE+(X SHR 2) }
- AND BX,3 {BL = X MOD 4 = plane to read from; BH = 0}
- MOV AL,4
- MOV AH,BL
- MOV BL,pa {BH=0 -> BX = graphic page}
- AND BX,3 {only pages 0..3}
- SHL BX,1
- ADD BX,OFFSET Segment_Adr-StartIndex*2
- MOV ES,[BX]
-
- CLI
- MOV DX,3CEh
- OUT DX,AX
- MOV AL,ES:[DI]
- STI
- @offscrn:
- END;
-
-
- PROCEDURE PutPixel(x,y:INTEGER; color:Byte); ASSEMBLER;
- { in: x,y = VIRTUAL pixel coordinates of the point to be written }
- { color = color value for the pixel to be drawn }
- { 1-PAGE = graphic page to be drawn upon }
- { StartVirtualX, StartVirtualY = upper left image corner }
- {out: - }
- {rem: The point (x,y) has been transformed to absolute screen coordinates }
- { and has been drawn (if it lies within the visible window) }
- { The pixel will NOT automatically be overtaken into the background }
- { image, that is: it will be visible only for one animation cycle! }
- { (For that reason, you should call this routine AFTER calling ANIMATE }
- { because otherwise, the drawn point will vanish at once!) }
- ASM
- MOV DI,y
- SUB DI,StartVirtualY {transform y into absolue coordinates}
- JS @offscrn
- CMP DI,YMAX
- JG @offscrn
- MOV BX,x
- SUB BX,StartVirtualX {transform x into absolute coordinates}
- JS @offscrn
- CMP BX,XMAX
- JG @offscrn
- SHL DI,1
- MOV DI,CS:[OFFSET gadr + DI]
- {DI = Y*LINESIZE, BX = X, coordinates admissible}
- MOV AX,BX
- SHR AX,1
- SHR AX,1
- ADD DI,AX {DI = Y*LINESIZE+(X SHR 2) }
- AND BX,3
- MOV AH,[OFFSET TranslateTab + BX]
- MOV AL,2
- MOV DX,3C4h
-
- MOV BX,1 {ES:=Segment_Adr[1-PAGE], because 1-PAGE=visible page}
- SUB BX,PAGE
- SHL BX,1
- ADD BX,OFFSET Segment_Adr-StartIndex*2
- MOV ES,[BX]
-
- CLI
- OUT DX,AX
- MOV AL,color
- STOSB
- STI
- @offscrn:
- END;
-
- PROCEDURE BackgroundPutPixel(x,y:INTEGER; color:Byte); ASSEMBLER;
- { in: x,y = VIRTUAL pixel coordinates of the point to be written }
- { color = color value for the pixel to be drawn }
- { StartVirtualX, StartVirtualY = upper left image corner }
- {out: - }
- {rem: The point (x,y) has been transformed to absolute screen coordinates and}
- { has been drawn into the background (if it is onscreen) }
- { The pixel will NOT be visible until the next animation cycle takes }
- { place (but then, it remains permanent) (For that reason, you should }
- { call this routine BEFORE calling ANIMATE. That way, evtl. changes to }
- { the background will be visible "at once"!) }
- { Because BACKGNDPAGE is used as background page, calling this }
- { routine only makes sense when using background mode STATIC!}
- ASM
- MOV DI,y
- SUB DI,StartVirtualY {transform y into absolue coordinates}
- JS @offscrn
- CMP DI,YMAX
- JG @offscrn
- MOV BX,x
- SUB BX,StartVirtualX {transform x into absolute coordinates}
- JS @offscrn
- CMP BX,XMAX
- JG @offscrn
- SHL DI,1
- MOV DI,CS:[OFFSET gadr + DI]
- {DI = Y*LINESIZE, BX = X, coordinates admissible}
- MOV AX,BX
- SHR AX,1
- SHR AX,1
- ADD DI,AX {DI = Y*LINESIZE+(X SHR 2) }
- AND BX,3
- MOV AH,[OFFSET TranslateTab + BX]
- MOV AL,2
- MOV DX,3C4h
- MOV ES,BACKGNDADR
- CLI
- OUT DX,AX
- MOV AL,color
- STOSB
- STI
- @offscrn:
- END;
-
- PROCEDURE PagePutPixel(x,y:INTEGER; color,pa:Byte); ASSEMBLER;
- { in: x,y = VIRTUAL pixel coordinates of the point to be written }
- { color = color value for the pixel to be drawn }
- { pa = graphic page (0..3) to be drawn upon }
- { PAGEADR= graphic page(segment) to be drawn upon }
- { StartVirtualX, StartVirtualY = upper left image corner }
- {out: - }
- {rem: The point (x,y) has been transformed to absolute screen coordinates }
- { and has been drawn (if it lies within the visible window) }
- { If you want to draw at the actually VISIBLE graphic page }
- { then you must call the routine with pa=1-PAGE! }
- { Again, the drawn pixel will _NOT_ automatically be taken }
- { over into the background image, that is: it will be visible }
- { only until the next animation cycle (=till calling ANIMATE) }
- { (For that reason, you should call this routine AFTER }
- { calling ANIMATE, because otherwise, your drawn pixel will }
- { vanish at once!) }
- { Sensible values for "pa" are either 0 or 1 (and evtl. BACK- }
- { GNDPAGE, if you are using background mode STATIC), however, }
- { the routine doesn't check that! }
- ASM
- MOV DI,y
- SUB DI,StartVirtualY {transform y into absolue coordinates}
- JS @offscrn
- CMP DI,YMAX
- JG @offscrn
- MOV BX,x
- SUB BX,StartVirtualX {transform x into absolute coordinates}
- JS @offscrn
- CMP BX,XMAX
- JG @offscrn
- SHL DI,1
- MOV DI,CS:[OFFSET gadr + DI]
- {DI = Y*LINESIZE, BX = X, coordinates admissible}
- MOV AX,BX
- SHR AX,1
- SHR AX,1
- ADD DI,AX {DI = Y*LINESIZE+(X SHR 2) }
- AND BX,3
- MOV AH,[OFFSET TranslateTab + BX]
- MOV AL,2
- MOV DX,3C4h
- MOV BL,pa {BH=0 -> BX=graphic page}
- SHL BX,1
- ADD BX,OFFSET Segment_Adr+StartIndex*2
- MOV ES,[BX]
-
- CLI
- OUT DX,AX
- MOV AL,color
- STOSB
- STI
- @offscrn:
- END;
-
-
- PROCEDURE OutTextXY(x,y:INTEGER; pa:BYTE; s:STRING);
- { in: (x,y) = (virtual) starting coordinates for the text to be written}
- { s = textstring to be displayed }
- { pa = graphic page where the text shall be written }
- { GraphTextColor=color for text }
- { GraphTextBackground=color to be used for text background; if }
- { this value equals GraphTextColor, only the text-pixels }
- { themselves will be drawn while the surrounding ones }
- { don't change (=normal behaviour of TP's OutText-procs) }
- { GraphTextOrientation="vertical" or "horizontal" }
- { StartVirtualX,StartVirtualY = upper left image corner }
- {out: text has been written to the screen }
- VAR z,b,bit,i:BYTE;
- data:Fontchar;
- BEGIN
- IF (pa<>0) AND (pa<>1) AND (pa<>BACKGNDPAGE)
- THEN BEGIN
- Error:=Err_InvalidPageNumber;
- exit
- END;
- FOR i:=1 TO Length(s) DO
- BEGIN
- data:=FontData[ord(s[i])];
- FOR z:=0 TO FontHeight-1 DO
- BEGIN
- b:=data[z];
- FOR bit:=0 TO FontWidth-1 DO
- IF b and FontMask[bit]<>0
- THEN PagePutPixel(x+bit,y+z,GraphTextColor,pa)
- ELSE IF (GraphTextColor<>GraphTextBackground)
- THEN PagePutPixel(x+bit,y+z,GraphTextBackground,pa);
- END;
- IF GraphTextOrientation=horizontal
- THEN INC(x,FontWidth)
- ELSE INC(y,FontHeight);
- END;
- END;
-
- PROCEDURE BackgroundOutTextXY(x,y:INTEGER; s:STRING);
- {rem: Functionally equivalent to OutTextXY(), but the text will be }
- { written to the background page instead of page PAGEADR! }
- { Because BACKGNDADR is used as background page, calling }
- { this routine only makes sense when using mode STATIC! }
- VAR z,b,bit,i:BYTE;
- data:Fontchar;
- BEGIN
- FOR i:=1 TO Length(s) DO
- BEGIN
- data:=FontData[ord(s[i])];
- FOR z:=0 TO FontHeight-1 DO
- BEGIN
- b:=data[z];
- FOR bit:=0 TO FontWidth-1 DO
- IF b and FontMask[bit]<>0
- THEN BackgroundPutPixel(x+bit,y+z,GraphTextColor)
- ELSE IF (GraphTextColor<>GraphTextBackground)
- THEN BackgroundPutPixel(x+bit,y+z,GraphTextBackground);
- END;
- IF GraphTextOrientation=horizontal
- THEN INC(x,FontWidth)
- ELSE INC(y,FontHeight);
- END;
- END;
-
-
- FUNCTION Hitdetect(s1,s2:INTEGER):BOOLEAN; ASSEMBLER;
- { in: s1,s2 = sprite position numbers of two sprites}
- { SpriteN[s1],SpriteX[s1],SpriteY[s1] = sprite data of sprite s1 }
- { SpriteN[s2],SpriteX[s2],SpriteY[s2] = sprite data of sprite s2 }
- {out: TRUE/FALSE for "sprites collide"/"sprites do not collide" }
- {rem: This check is pixel-precise and doesn't depend on the sprites being}
- { visible (=onscreen) or not! }
- { inactive sprites (SpriteN[s?]=0) cannot collide }
- { A sprite can't collide with itself, (thus: s1=s2 -> FALSE) }
- ASM
- MOV SI,s1 {get 1st parameter s1 from stack}
- MOV DI,s2 {get 2nd parameter s2 from stack}
- CMP SI,DI
- JE @NOHIT1 {sprite can't collide with itself }
- SHL SI,1
- mov cx,[SI + OFFSET SpriteN]
- jcxz @NOHIT1 {sprite <>0, that is: sprite active?}
- SHL DI,1
- MOV BX,[DI + OFFSET SpriteN]
- OR BX,BX {dto. for other sprite }
- JNE @PRUEF2
- @NOHIT1:
- JMP @NOHIT7 {inactive sprites can't collide }
- {either -> return FALSE }
- {here: SI (DI) = pointer to 1. (2.) sprite in ?YWRTD[..],}
- { CX (BX) = spritenumber of sprite 1 (2) }
- {(a bit later, DS (ES) becomes segment addr. of sprite data of spr. 1 (2) )}
- @PRUEF2:
- MOV AX,[SI + OFFSET SpriteY]
- MOV DX,[DI + OFFSET SpriteY]
- mov si,[SI + OFFSET SpriteX] {SI=x1}
- mov di,[DI + OFFSET SpriteX] {DI=x2}
- shl bx,1 {BX=Spritenumber2*2}
- mov es,[BX + OFFSET SPRITEAD] {ES=segment of 2nd sprite's data}
- mov bx,cx {(CX=spritenumber1)}
- shl bx,1 {BX=spritenumber1*2}
- MOV ds,[BX + OFFSET SPRITEAD]
-
- mov [y1],ax
- mov [y2],dx
- sub dx,ax
- mov CS:WORD PTR @y2_y1+1,dx
- mov [x1],si
- mov [x2],di
- mov dx,di
- sub dx,si
- mov CS:WORD PTR @x2_x1+1,dx
- mov ax,es:[Left] {AX=pointer to left boundary data}
- mov CS:WORD PTR @lirand2+1,ax
- mov ax,es:[Right] {AX=pointer to right boundary data}
- mov CS:WORD PTR @rerand2+1,ax
- mov ax,es:[Top] {AX=pointer to upper boundary data}
- mov CS:WORD PTR @orand2+1,ax
- mov ax,es:[Bottom] {AX=pointer to lower boundary data}
- mov CS:WORD PTR @urand2+1,ax
- mov ax,es:[Breite] {AX=max. width in groups of 4 }
- shl al,1
- shl al,1
- mov CS:WORD PTR @breite2+1,ax {*4 = width in points }
- mov ax,es:[Hoehe]
- mov CS:WORD PTR @hoehe2+1,ax {height of sprite2 in points }
-
- MOV AX,[Left] {AX=pointer to left boundary data}
- MOV CS:WORD PTR @LIRAND1+1,AX
- MOV AX,[Right] {AX=pointer to right boundary data}
- MOV CS:WORD PTR @RERAND1+1,AX
- MOV AX,[Top] {AX=pointer to upper boundary data}
- MOV CS:WORD PTR @ORAND1+1,AX
- MOV AX,[Bottom] {AX=pointer to lower boundary data}
- MOV CS:WORD PTR @URAND1+1,AX
- MOV BX,[Breite] {BX=max. width in groups of 4 }
- SHL BX,1
- SHL BX,1 {*4 = width in points }
- MOV CS:WORD PTR @BREITE1+2,BX
-
- lea bx,[si+bx-1] {BX:=x1+breite1-1 (=x1last)}
- @breite2:
- mov bp,1234h {dummy value}
- mov cx,bp {CX=breite2 will be needed later again }
- lea bp,[di+bp-1] {BP:=x2+breite2-1 (=x2last)}
- cmp bx,bp
- jle @noex1
- mov bp,bx
- @noex1: {here: BP=max(x1last,x2last) (=maxx)}
- cmp si,di
- jle @X1_klgl_X2
- xchg si,di
- @X1_klgl_X2: {here: SI=min(x1,x2) (=minx)}
- stc
- sbb si,bp {SI:=minx-maxx-1=-(maxx-minx+1)}
- @breite1:
- add cx,1234h {(dummy value) CX:=breite1+breite2}
- add cx,si {CX:=breite1+breite2-(maxx-minx+1)}
- dec cx {CX:=breite1+breite2-(maxx-minx+1)-1 (=ueberlappx-1)}
- js @NOHIT2 {no collision, if ueberlappx<=0 }
- mov [ueberlappx_1],cx
-
- mov ax,[Hoehe]
- mov bx,ax {BX:=hoehe1}
- mov di,[y1] {DI:=y1}
- add ax,di {AX:=y1+hoehe1}
- dec ax {AX:=y1+hoehe1-1 (=y1last)}
- @hoehe2:
- mov si,1234h
- mov dx,[y2]
- add dx,si {DX:=y2+hoehe2}
- dec dx {DX:=y2+hoehe2-1 (=y2last)}
- cmp ax,dx
- jge @noex2
- mov ax,dx
- @noex2: {here: AX=max(y1last,y2last) (=maxy)}
- mov dx,[y2]
- cmp di,dx {(DI=y1)}
- jle @noex3
- mov di,dx
- @noex3: {here: DI=min(y1,y2) (=miny)}
- sub di,ax {DI:=miny-maxy=-(maxy-miny)}
- lea ax,[bx+si-2] {AX:=hoehe1+hoehe2-2}
- add ax,di {AX:=hoehe1+hoehe2-(maxy-miny+1)-1 (=ueberlappy-1)}
- js @NOHIT2 {no collision, if ueberlappy<=0 }
- mov [ueberlappy_1],ax
-
- {here: AX=ueberlappy-1, CX=ueberlappx-1}
- @x2_x1:
- mov dx,1234h {dummy value}
- xor bx,bx {from now on: BX=0!}
- or dx,dx
- js @X2_X1_kl_0 {if x2-x1>=0 then...}
- mov [hit2xfirst],bx {...hit2xfirst:=0}
- mov [hit1xfirst],dx {...hit1xfirst:=x2-x1}
- jmp @Yhits {SHORT}
-
- {jump-rail for NOHIT (this is a good place) }
- @NOHIT2:
- JMP @NOHIT7
-
- {now back at "normal" program }
- @X2_X1_kl_0: {else (x2-x1<0)...}
- mov [hit1xfirst],bx {...hit1xfirst:=0}
- neg dx {DX:=x1-x2}
- mov [hit2xfirst],dx {...hit2xfirst:=x1-x2}
-
- @Yhits: {here: AX=ueberlappy-1}
- @y2_y1:
- mov dx,1234h {dummy value}
- or dx,dx
- js @Y2_Y1_kl_0 {if y2-y1>=0 then...}
- mov [hit2yfirst],bx {...hit2yfirst:=0}
- mov [hit1yfirst],dx {...hit1yfirst:=y2-y1}
- jmp @iterate {SHORT}
- @Y2_Y1_kl_0: {else (y2-y1<0)...}
- mov [hit1yfirst],bx {...hit1yfirst:=0}
- neg dx {DX:=y1-y2}
- mov [hit2yfirst],dx {...hit2yfirst:=y1-y2}
-
- {Now check the overlapping rows and columns more closely by iteration: }
- @iterate:
- mov cx,[ueberlappy_1] {number of rows -1 to compare }
- shl cx,1 {*2, because word-sized!}
- @lirand1:
- mov si,1234h {dummy value}
- @lirand2:
- mov di,1234h {dummy value}
- @rerand1:
- mov bx,1234h {dummy value}
- @rerand2:
- mov bp,1234h {dummy value}
- sub bx,si {BX:=rerand1-lirand1}
- sub bp,di {BP:=rerand2-lirand2}
- mov ax,[hit1yfirst]
- shl ax,1
- add si,ax {SI:=1st row where sprite1 overlaps sprite2 }
- mov ax,[hit2yfirst]
- shl ax,1
- add di,ax {DI:=1st row where sprite2 overlaps sprite1 }
- add si,cx {dto., last row }
- add di,cx
- @one_line:
- mov ax,[si] {DS:AX:=x1li[row] }
- mov dx,es:[di] {ES:DX:=x2li[row] }
- add ax,[x1] {AX:=x1li[row]+x1 (=c) }
- add dx,[x2] {DX:=x2li[row]+x2 (=d) }
- cmp ax,dx
- jge @C_grgl_D
- mov ax,dx
- @C_grgl_D: {here: AX=max(c,d)}
- mov cx,[si+bx] {DS:CX:=x1re[row] }
- mov dx,es:[di+bp] {ES:DX:=x2re[row] }
- add cx,[x1] {CX:=x1re[row]+x1 (=a) }
- add dx,[x2] {DX:=x2re[row]+x2 (=b) }
- cmp cx,dx
- jle @A_klgl_B
- mov cx,dx
- @A_klgl_B: {here: CX=min(a,b)}
- cmp cx,ax {min(a,b)>=max(c,d) ?}
- jge @found_Xhit {yes: collision in X-direction found!}
- dec si {next row (-> word-sized values!)}
- dec si
- dec di
- dec di
- dec WORD PTR [ueberlappy_1]
- jns @one_line
- {no collision in X-direction -> no collision at all! }
- jmp @NOHIT7
-
- {otherwise: collision in X-direction, now check Y-dir. also (as above) and }
- {report "collision!" only, if there is at least 1 collision in Y-dir., too }
- @found_Xhit:
- mov cx,[ueberlappx_1] {number of columns -1 to compare }
- shl cx,1 {*2, because word-sized!}
- @orand1:
- mov si,1234h {dummy value}
- @orand2:
- mov di,1234h {dummy value}
- @urand1:
- mov bx,1234h {dummy value}
- @urand2:
- mov bp,1234h {dummy value}
- sub bx,si {BX:=urand1-orand1}
- sub bp,di {BP:=urand2-orand2}
- mov ax,[hit1xfirst]
- shl ax,1 {*2, because word-sized!}
- add si,ax {SI:=orand1+2*hit1xfirst}
- mov ax,[hit2xfirst]
- shl ax,1 {*2, because word-sized!}
- add di,ax {DI:=orand2+2*hit2xfirst}
- add si,cx
- add di,cx
- @one_column: mov ax,[si] {AX:=y1ob[column]}
- cmp ax,16000 {dummy value for "empty column"?}
- je @next_column {yes, thus: surely no collision }
- mov dx,es:[di] {DX:=y2ob[column]}
- cmp dx,16000 {check 2nd sprite too: "empty column"? }
- je @next_column {yes, no collision}
- add ax,[y1] {AX:=y1ob+y1 (=c)}
- add dx,[y2] {DX:=y2ob+y2 (=d)}
- cmp ax,dx
- jge @C_grgl_D2
- mov ax,dx
- @C_grgl_D2: {here: AX=max(c,d)}
- mov cx,[si+bx] {DS:CX:=y1un[column]}
- mov dx,es:[di+bp] {ES:DX:=y2un[column]}
- add cx,[y1] {CX:=y1un+y1 (=a)}
- add dx,[y2] {DX:=y2un+y2 (=b)}
- cmp cx,dx
- jle @A_klgl_B2
- mov cx,dx
- @A_klgl_B2: {here: CX=min(a,b)}
- cmp cx,ax {min(a,b)>=max(c,d) ?}
- jge @HIT2 {yes: collision detected!}
- @next_column:
- dec si {no, next column (-> word-sized values!)}
- dec si
- dec di
- dec di
- dec WORD PTR [ueberlappx_1]
- jns @one_column
-
- @NOHIT7:
- XOR AX,AX {return 0 = FALSE as result }
- JMP @TREFF_END {SHORT}
- @HIT2:
- MOV AX,1 {return 1 = TRUE as result }
-
- @TREFF_END:
- {$IFOPT G+}
- mov bp,sp {only necessary for compiler switch G+!}
- {$ENDIF}
- mov dx,seg @DATA {else, BP will be restored by TP itself}
- mov ds,dx
- END;
-
-
- PROCEDURE Animate;
- { in: PAGEADR = actual graphicpage(address) on which to draw upon }
- { BACKGNDADR = background page(address) }
- { BACKGROUNDMODE = STATIC/SCROLLING for solid/scrollable background }
- { SpriteN[] = spritenumber of sprite to be displayed }
- { SpriteX[],SpriteY[] = their (virtual) coordinates }
- { StartVirtualX,StartVirtualY = upper left image corner }
- { (PAGE = actually displayed graphic page) }
- {out: PAGE = 0/1, if PAGE has been 1/0, respectively }
- { PAGEADR = new, actual graphic page(address) }
- {rem: Animate erases the old contents of the page (using the background page }
- { information), draws all visible sprites, synchronizes to the display- }
- { enable signal and switches the display to that now completed page }
- VAR offsetXTiles,offsetYTiles,offsetXPix,offsetYPix:INTEGER;
- leftcut,rightcut,topcut,bottomcut,tiles:WORD;
- x,y,xpix,ypix,xtil,ytil,actindex,randindex,index:INTEGER;
- offscreenFlag:BYTE;
- yt,xt:INTEGER;
- BEGIN
- ASM
- CLD
- {first copy the background picture to the actual graphic page:}
- CMP BackgroundMode,STATIC {which background mode? }
- JE @static_bckgnd
- JMP @scrolling_bckgnd
-
- @static_bckgnd:
- MOV AX,0F02h {write to all 4 planes simultaneously }
- MOV DX,3C4h
- OUT DX,AX
- MOV AX,4105h {choose write mode 1 }
- MOV DX,3CEh
- OUT DX,AX
-
- MOV ES,PAGEADR {fill graphic page with background pattern}
- MOV DS,BACKGNDADR
- XOR SI,SI
- MOV DI,SI
- MOV CX,PAGESIZE
-
- REP MOVSB
-
- MOV AX,SEG @DATA
- MOV DS,AX
- MOV AX,4005h {select write mode 0}
- MOV DX,3CEh
- OUT DX,AX
-
- JMP @Sprites_zeichnen
-
- {---------------------------------}
-
- @scrolling_bckgnd: {now: create background image from tiles }
- MOV AX,StartVirtualY
- MOV BX,AX {AX=BX=StartVirtualY}
- SUB AX,BackY1
- ADD AX,15 {offsetYTiles:=(StartVirtualY-BackY1+15) DIV 16}
- SAR AX,1
- SAR AX,1
- SAR AX,1
- SAR AX,1
- MOV offsetYTiles,AX
- MOV ytil,AX {ytil:=offsetYTiles}
- DEC AX
- IMUL XTiles
- MOV actIndex,AX {actIndex:=(ytil-1)*XTiles, "+xtil" comes later }
-
- MOV AX,16
- SUB AX,BX {BX=StartVirtualY}
- AND AX,$F
- MOV ypix,AX {ypix:=(16-StartVirtualY) AND $F}
- SUB AX,200
- AND AX,$F
- MOV bottomcut,AX {bottomcut:=(ypix-200) AND $F}
-
- AND BX,$F {offsetYPix:=topcut:=StartVirtualY AND $F}
- MOV topcut,BX
- MOV offsetYPix,BX
-
- MOV AX,StartVirtualX
- MOV BX,AX {AX=BX=StartVirtualX}
- SUB AX,BackX1
- ADD AX,15 {offsetXTiles:=(StartVirtualX-BackX1+15) DIV 16}
- SAR AX,1
- SAR AX,1
- SAR AX,1
- SAR AX,1
- MOV offsetXTiles,AX
- MOV xtil,AX {xtil:=offsetXTiles}
- ADD actIndex,AX {actIndex:=(ytil-1)*XTiles+xtil}
-
- MOV AX,16
- SUB AX,BX {BX=StartVirtualX}
- AND AX,$F
- MOV xpix,AX {xpix=rightcut:=(16-StartVirtualX) AND $F}
- MOV rightcut,AX
-
- AND BX,$F {offsetXPix:=leftcut:=StartVirtualX AND $F}
- MOV leftcut,BX
- MOV offsetXPix,BX
-
- MOV AX,(XMAX+1)/16-1
- SUB BL,1 {C=1, if leftcut=0 }
- ADC AX,0
- MOV tiles,AX {tiles:=19+ord(leftcut=0)}
-
-
- CMP topcut,0 {if topcut=0, the upper tile row doesn't}
- JE @do_innertiles {need to be drawn separately }
-
- {top most tile row:}
- MOV DX,xtil
- MOV xt,DX
- MOV AX,ytil
- DEC AX
- MOV yt,AX
- MOV CL,1
- JS @offscreen
- CMP AX,YTiles
- JAE @offscreen
- DEC CL
- @offscreen: {CL=0/1 for offscreenFlag=false/true=(yt<0) OR (yt>=YTiles) }
- MOV offscreenFlag,CL
-
- CMP leftcut,0 {if leftcut=0, the upper left corner does}
- JE @do_upperinnertiles {not need to be drawed separately }
-
- {draw upper left corner-tile: } {CL=offscreenFlag, DX=xt}
- XOR SI,SI {determine tile index:}
- DEC CL {IF offscreenFlag OR (xt-1<0) OR (xt-1>=XTiles) }
- JZ @go1 { THEN index:=0 ELSE index:=actIndex}
- DEC DX
- JS @go1
- CMP DX,XTiles
- JAE @go1
- MOV SI,actIndex {=yt*XTiles+(xt-1)}
- @go1:
-
- {PROCEDURE DrawUpperLeftTile(leftcut,topcut:INTEGER; index:WORD);}
- { in: leftcut = number of left tile-columns to be cut off }
- { topcut = dto., at the top}
- { SI = index = tile number}
- {out: tile has been drawn at (0,0) on the actual page PAGEADR }
- {rem: tile has been clipped at its left and top accordingly}
- { leftcut must lie in the range 0..15, 16 is allowed (but senseless) }
- { topcut must lie in the range 0..15, 16 is not allowed}
- MOV AH,[OFFSET BackTile +SI] {AH:=BackTile[index]}
- XOR AL,AL
-
- SHR AH,1 {AX:=tile*64 =tile SHL 6 =(tile SHL 8) SHR 2 }
- RCR AL,1 {therefore: set AH:=tile and afterwards, shift AX }
- SHR AH,1 {2 bits to the right!}
- RCR AL,1
- MOV SI,topcut
- MOV CX,16
- SUB CX,SI {CX:=16-topcut = number of rows to draw }
- SHL SI,1
- SHL SI,1 {add 4 bytes to the (offset part of the) }
- ADD SI,AX {source addr. in page 3 for each cut off top-row}
-
- XOR DI,DI {the first dest. addr. is DI:=0*LINESIZE+(0 div 4)=0 }
-
- MOV AX,leftcut
- MOV BX,AX {have a copy of leftcut in BX }
- SHR AX,1
- SHR AX,1
- ADD SI,AX {increment SI by cutoff (=leftcut div 4) bytes }
-
- {Now there is no further variable on stack, so BP can be used }
- {for other purposes!}
- PUSH BP {will be needed when leaving the procedure! }
- MOV BP,16+3
- SUB BP,BX {BP:=16+3-leftcut, because the number of bytes per row }
- {of plane i is computed by (16+3-i-leftcut) SHR 2 }
-
-
- MOV ES,PAGEADR {(segment part of) dest. address is active page}
- MOV DS,SCROLLADR {(segment part of) source addr. is page SCROLLPAGE}
-
- MOV DX,3CEh
- AND BL,3
- MOV AH,BL {AH:=leftcut mod 4}
- MOV AL,4
-
- JNE @mode0a {only if leftcut mod 4=0 is it possible to use WriteMode1 }
-
- {--- short-cut possible, using write mode1: DX=3CEh, BP=16+3-leftcut }
- { BP being "3 units to big" doesn't matter, because this code will }
- { only be run if leftcut mod 4=0, thus 16+3-leftcut=...11b, the }
- { "11b" will be cut off while shifting right, anyway! }
- MOV AX,4105h
- OUT DX,AX {choose write mode 1}
- MOV DX,3C4h
- MOV AX,0F02h {work on all 4 planes simultaneously }
- OUT DX,AX
-
- SHR BP,1 {use BP directly }
- SHR BP,1 {BP:=bytes_per_plane3_row }
-
- MOV AX,LINESIZE {adjustment for row target addresses }
- SUB AX,BP { := LINESIZE-bytes_per_plane3_row }
- MOV DX,4 {adjustment for source addresses of the tiles}
- SUB DX,BP { := 4-bytes_per_plane3_row }
-
- {don't save source- and destination addresses}
- MOV BX,CX {BX:=row counter }
- @eineZeile4a1:
- MOV CX,BP {CX:=bytes_per_plane0_row }
- REP MOVSB {move data of one row }
- ADD DI,AX {set DI to next destination row }
- ADD SI,DX {set SI to next tile's source addr. }
- DEC BX
- JNZ @eineZeile4a1
-
- {--- short cut has been taken: thus, reset write mode 0! }
- MOV AX,4005h
- MOV DX,3CEh
- OUT DX,AX
- {---}
- JMP @UpperLeftTileDone
-
- @mode0a:
- OUT DX,AX {choose plane from which to read}
- PUSH AX {and preserve it for later}
-
- MOV DX,3C4h
- MOV AX,0102h {choose write plane 0 }
- OUT DX,AX
-
- MOV BX,BP
- SHR BX,1
- SHR BX,1 {BX:=bytes_per_plane0_row = (16+3-leftcut) DIV 4 }
-
- MOV AX,LINESIZE {adjustment for row target addresses }
- SUB AX,BX { := LINESIZE-bytes_per_plane0_row }
- MOV DX,4 {adjustment for source addresses of the tiles}
- SUB DX,BX { := 4-bytes_per_plane0_row }
-
- PUSH SI {save source- and destination address for other planes}
- PUSH DI
- PUSH BP {save BP }
- PUSH CX {CX = save row counter }
- MOV BP,CX {BP:=row counter }
- @eineZeile1a:
- MOV CX,BX {CX:=bytes_per_plane0_row }
- REP MOVSB {move data of one row }
- ADD DI,AX {set DI to next destination row }
- ADD SI,DX {set SI to next tile's source addr. }
- DEC BP
- JNZ @eineZeile1a
- POP CX
- POP BP
- POP DI
- POP SI
-
- MOV DX,3C4h
- MOV AX,0202h {choose write plane 1 }
- OUT DX,AX
-
- MOV DX,3CEh {next read plane: }
- POP AX
- INC AH
- AND AH,3 {increment by 1 MOD 4}
- JNE @nowrap1a
- INC SI {plane 0 follows after plane 3 again, but}
- {the source address has increased by 1 byte }
- @nowrap1a:
- OUT DX,AX
- PUSH AX
-
-
- DEC BP {BP:=16+2-leftcut}
- MOV BX,BP
- SHR BX,1
- SHR BX,1 {BX:=bytes_per_plane1_row }
-
- MOV AX,LINESIZE {adjustment for row target addresses }
- SUB AX,BX { := LINESIZE-bytes_per_plane1_row }
- MOV DX,4 {adjustment for source addresses of the tiles}
- SUB DX,BX { := 4-bytes_per_plane1_row }
-
- PUSH SI {save source- and destination address for other planes}
- PUSH DI
- PUSH BP {save BP }
- PUSH CX {save row counter }
- MOV BP,CX {BP:=row counter }
- @eineZeile2a:
- MOV CX,BX {CX:=bytes_per_plane0_row }
- REP MOVSB {move data of one row }
- ADD DI,AX {set DI to next destination row }
- ADD SI,DX {set SI to next tile's source addr. }
- DEC BP
- JNZ @eineZeile2a
- POP CX
- POP BP
- POP DI
- POP SI
-
- MOV DX,3C4h
- MOV AX,0402h {choose write plane 2 }
- OUT DX,AX
-
- MOV DX,3CEh {next read plane: }
- POP AX
- INC AH
- AND AH,3 {increment by 1 MOD 4}
- JNE @nowrap2a
- INC SI {plane 0 follows after plane 3 again, but}
- {the source address has increased by 1 byte }
- @nowrap2a:
- OUT DX,AX
- PUSH AX
-
-
- DEC BP {BP:=16+1-leftcut}
- MOV BX,BP
- SHR BX,1
- SHR BX,1 {BX:=bytes_per_plane2_row }
-
- MOV AX,LINESIZE {adjustment for row target addresses }
- SUB AX,BX { := LINESIZE-bytes_per_plane2_row }
- MOV DX,4 {adjustment for source addresses of the tiles}
- SUB DX,BX { := 4-bytes_per_plane2_row }
-
- PUSH SI {save source- and destination address for other planes}
- PUSH DI
- PUSH BP {save BP }
- PUSH CX {save row counter }
- MOV BP,CX {BP:=row counter }
- @eineZeile3a:
- MOV CX,BX {CX:=bytes_per_plane0_row }
- REP MOVSB {move data of one row }
- ADD DI,AX {set DI to next destination row }
- ADD SI,DX {set SI to next tile's source addr. }
- DEC BP
- JNZ @eineZeile3a
- POP CX
- POP BP
- POP DI
- POP SI
-
- MOV DX,3C4h
- MOV AX,0802h {choose write plane 3 }
- OUT DX,AX
-
- MOV DX,3CEh {next read plane: }
- POP AX
- INC AH
- AND AH,3 {increment by 1 MOD 4}
- JNE @nowrap3a
- INC SI {plane 0 follows after plane 3 again, but}
- {the source address has increased by 1 byte }
- @nowrap3a:
- OUT DX,AX
-
-
- DEC BP {BP:=16-leftcut}
- @lastplane1:
-
- SHR BP,1 {use BP directly }
- SHR BP,1 {BP:=bytes_per_plane3_row }
-
- MOV AX,LINESIZE {adjustment for row target addresses }
- SUB AX,BP { := LINESIZE-bytes_per_plane3_row }
- MOV DX,4 {adjustment for source addresses of the tiles}
- SUB DX,BP { := 4-bytes_per_plane3_row }
-
- {don't save source- and destination addresses}
- MOV BX,CX {BX:=row counter }
- @eineZeile4a:
- MOV CX,BP {CX:=bytes_per_plane0_row }
- REP MOVSB {move data of one row }
- ADD DI,AX {set DI to next destination row }
- ADD SI,DX {set SI to next tile's source addr. }
- DEC BX
- JNZ @eineZeile4a
-
- @UpperLeftTileDone:
- POP BP
- MOV AX,SEG @Data {restore DS }
- MOV DS,AX
-
- {Now work on all other upper tiles, which are cut at their top (but }
- {not at the sides!): }
- @do_upperinnertiles:
- MOV AX,xpix
- MOV x,AX
- INC actIndex
-
- @repeat1: {loop will be taken exactly "tiles" times }
- MOV CL,offscreenFlag
- XOR SI,SI {determine tile index:}
- DEC CL {IF offscreenFlag OR (xt<0) OR (xt>=XTiles) }
- JZ @go2 { THEN index:=0 ELSE index:=actIndex =yt*XTiles+xt}
- MOV DX,xt
- OR DX,DX
- JS @go2
- CMP DX,XTiles
- JAE @go2
- MOV SI,actIndex
- @go2:
-
-
- {PROCEDURE DrawUpperTile(x,topcut:INTEGER; index:WORD);}
- { in: (x,0) = upper left corner of the tile to be drawn,}
- { topcut= number of lines to be cut off}
- { SI = index = tile number}
- {out: tile has been drawn on actual page PAGEADR }
- {rem: Tile must be onscreen with its left, right (and lower) parts }
- { topcut must lie in stack (because DS is used for other purposes!)}
- { topcut must have a value in the range 0..15, 16 is not allowed!}
- MOV AH,[OFFSET BackTile +SI] {AH:=BackTile[index]}
- XOR AL,AL
-
- SHR AH,1 {AX:=tile*64 =tile SHL 6 =(tile SHL 8) SHR 2 }
- RCR AL,1 {therefore: set AH:=tile and afterwards, shift AX }
- SHR AH,1 {2 bits to the right!}
- RCR AL,1 {That's also the offset part of the source ad. in page3}
-
- MOV SI,topcut {additionaly: the rows cut off at the upper edge:}
- MOV CX,16 {4 bytes for each row }
- SUB CX,SI {CX:=16-topcut = rows to draw }
- SHL SI,1
- SHL SI,1
- ADD SI,AX {SI = pointer to first tile byte to copy }
-
- {The first destination address is DI:=0*LINESIZE+(x div 4)=x div 4}
- MOV DI,x
- MOV BX,DI {have a copy of X in BX }
- SHR DI,1
- SHR DI,1
-
- {Now there is no further variable on stack, so BP can be used }
- {for other purposes!}
- PUSH BP {will be needed when leaving the procedure! }
- MOV BP,CX
- SHL BP,1
- SHL BP,1 {BP := (rows to draw)*4 }
-
- MOV ES,PAGEADR {(segment part of) dest. address is active page}
- MOV DS,SCROLLADR {(segment part of) source addr. is page SCROLLPAGE}
-
- MOV DX,3C4h
- MOV AL,2
- AND BX,3 {BX:=1st write plane (1st READ plane=0!) }
- JNE @mode0b {only if x mod 4=0 is it possible to use WriteMode1 }
-
- {--- short-cut possible, using write mode1 }
- MOV AH,0Fh {work on all 4 planes simultaneously }
- OUT DX,AX
- MOV AX,4105h
- MOV DX,3CEh
- OUT DX,AX {choose write mode 1}
- MOV BX,CX {BX:=CX=rows to draw }
-
- MOV AX,LINESIZE-4
- MOV CX,BX {CX:=number of rows to draw }
- @eineZeile4b1:
- MOVSB {no MOVSW, as we use write mode 1!}
- MOVSB
- MOVSB
- MOVSB
- ADD DI,AX {set DI to next row }
- LOOP @eineZeile4b1
-
- {--- short cut has been taken: thus, reset write mode 0! }
- MOV AX,4005h
- MOV DX,3CEh
- OUT DX,AX
- {---}
- JMP @UpperTileDone
-
- @mode0b:
- MOV AH,CS:[OFFSET CS_TranslateTab+BX]
- OUT DX,AX
- PUSH AX {save actual write plane }
-
- MOV DX,3CEh
- MOV AX,0004h {choose plane 0 for reading }
- OUT DX,AX
-
- MOV AX,LINESIZE-4 {adjustment for row addresses }
- MOV BX,CX {save number of rows to draw into BX }
- @eineZeile1b:
- MOVSW
- MOVSW
- ADD DI,AX {set DI to next row }
- LOOP @eineZeile1b
-
- MOV AX,0104h {DX=3CEh -> choose read plane 1}
- OUT DX,AX
-
- MOV DX,3C4h {next write plane: }
- POP AX
- SHL AH,1
- CMP AH,16
- JNE @nowrap1b
- MOV AH,1 {plane 0 follows after plane 3 again, but}
- INC DI {the destination address has increased by 1 byte}
- @nowrap1b:
- OUT DX,AX
- PUSH AX
- SHL BX,1 {reset DI to the source address: }
- SUB DI,CS:[OFFSET GADR + BX] {thus, decrement DI by (rows to draw)* }
- SHR BX,1 {LINESIZE (N.B.: BX=number of rows to draw)}
- SUB SI,BP {reset SI, too }
-
-
- MOV AX,LINESIZE-4
- MOV CX,BX {CX:=number of rows to draw }
- @eineZeile2b:
- MOVSW
- MOVSW
- ADD DI,AX {set DI to next row }
- LOOP @eineZeile2b
-
- POP AX
- SHL AH,1
- CMP AH,16
- JNE @nowrap2b
- MOV AH,1 {plane 0 follows after plane 3 again, but}
- INC DI {the destination address has increased by 1 byte}
- @nowrap2b:
- OUT DX,AX {DX=3C4h -> set write plane }
- PUSH AX
- MOV DX,3CEh
- MOV AX,0204h {set read plane 2 }
- OUT DX,AX
- SHL BX,1 {reset DI to the source address: }
- SUB DI,CS:[OFFSET GADR + BX] {thus, decrement DI by (rows to draw)* }
- SHR BX,1 {LINESIZE (N.B.: BX=number of rows to draw)}
- SUB SI,BP {reset SI, too }
-
-
- MOV AX,LINESIZE-4
- MOV CX,BX {CX:=number of rows to draw }
- @eineZeile3b:
- MOVSW
- MOVSW
- ADD DI,AX {set DI to next row }
- LOOP @eineZeile3b
-
- MOV AX,0304h
- OUT DX,AX {DX=3CEh -> choose read plane 3}
- MOV DX,3C4h
- POP AX
- SHL AH,1
- CMP AH,16
- JNE @nowrap3b
- MOV AH,1 {plane 0 follows after plane 3 again, but}
- INC DI {the destination address has increased by 1 byte}
- @nowrap3b:
- OUT DX,AX {DX=3C4h -> set write plane }
- SHL BX,1 {reset DI to the source address: }
- SUB DI,CS:[OFFSET GADR + BX] {thus, decrement DI by (rows to draw)* }
- SHR BX,1 {LINESIZE (N.B.: BX=number of rows to draw)}
- SUB SI,BP {reset SI, too }
-
-
- @lastPlane2:
- MOV AX,LINESIZE-4
- MOV CX,BX {CX:=number of rows to draw }
- @eineZeile4b:
- MOVSW
- MOVSW
- ADD DI,AX {set DI to next row }
- LOOP @eineZeile4b
-
- @UpperTileDone:
- POP BP
- MOV AX,SEG @Data {restore DS }
- MOV DS,AX
-
- INC xt {increment tile counter in X-direction}
- INC actIndex {because actIndex=yt*XTiles+xt do increment actIndex, too}
- MOV AX,x {increment actual X-coordinate, too: x:=x+16 }
- ADD AX,16
- MOV x,AX
- CMP AX,XMAX+1-16
- JBE @repeat1 {until upper right corner has been reached}
-
- {Now the upper right corner-tile - if not already drawn: }
- CMP AX,XMAX+1
- JE @label1
-
- MOV CL,offscreenFlag {yes, corner remains to be drawn }
- XOR SI,SI {determine tile index:}
- DEC CL {IF offscreenFlag OR (xt<0) OR (xt>=XTiles) }
- JZ @go3 { THEN index:=0 ELSE index:=actIndex =yt*XTiles+xt}
- MOV DX,xt
- OR DX,DX
- JS @go3
- CMP DX,XTiles
- JAE @go3
- MOV SI,actIndex
- @go3:
-
-
- {PROCEDURE DrawUpperRightTile(x,rightcut,topcut:INTEGER; index:WORD);}
- { in: (x,0) = upper left corner of the tile to be drawn}
- { rightcut = number of right tile-columns to be cut off }
- { topcut = dto., at the top}
- { SI = index = tile number}
- {out: tile has been drawn on actual page PAGEADR }
- {rem: tile has been clipped at its right and top accordingly}
- { topcut must lie in the range 0..15, 16 is not allowed}
- { rightcut must lie between 0..15, 16 is allowed (but senseless)! }
- { rightcut could also be computed (for x>xmax-16) by }
- { rightcut := x+15-xmax }
- MOV AH,[OFFSET BackTile +SI] {AH:=BackTile[index]}
- XOR AL,AL
-
- SHR AH,1 {AX:=tile*64 =tile SHL 6 =(tile SHL 8) SHR 2 }
- RCR AL,1 {therefore: set AH:=tile and afterwards, shift AX }
- SHR AH,1 {2 bits to the right!}
- RCR AL,1
- MOV SI,topcut
- MOV CX,16
- SUB CX,SI {CX:=16-topcut = number of rows to draw }
- SHL SI,1
- SHL SI,1 {add 4 bytes to the (offset part of the) }
- ADD SI,AX {source addr. in page 3 for each cut off top-row}
-
- MOV DI,x {first dest. addr. is DI:=0*LINESIZE +(x div 4)=x div 4 }
- MOV BX,DI {place a copy of x in BX}
- SHR DI,1
- SHR DI,1
-
- MOV AX,rightcut
-
- {Now there is no further variable on stack, so BP can be used }
- {for other purposes!}
- PUSH BP {will be needed when leaving the procedure! }
- MOV BP,16+3
- SUB BP,AX {BP:=16+3-rightcut, because the number of bytes per row }
- {of plane i is computed by (16+3-i-rightcut) SHR 2 }
- MOV AH,AL {save rightcut to AH }
-
- MOV ES,PAGEADR {(segment part of) dest. address is active page}
- MOV DS,SCROLLADR {(segment part of) source addr. is page SCROLLPAGE}
-
- MOV DX,3C4h
- MOV AL,2
- AND BX,3
-
- JNE @mode0c {only if x mod 4=0 _and_ rightcut mod 4=0, then we can }
- AND AH,3 {use write mode 1! }
- JNE @mode0c
-
- {--- short-cut possible, using write mode1: DX=3C4h, BP=16+3-rightcut }
- MOV AH,0Fh
- OUT DX,AX {work on all 4 planes simultaneously }
- MOV DX,3CEh
- MOV AX,4105h {choose write mode 1}
- OUT DX,AX
- SUB BP,3 {set BP to proper size }
-
- SHR BP,1 {use BP directly }
- SHR BP,1 {BP:=bytes_per_plane3_row }
-
- MOV AX,LINESIZE {adjustment for row target addresses }
- SUB AX,BP { := LINESIZE-bytes_per_plane3_row }
- MOV DX,4 {adjustment for source addresses of the tiles}
- SUB DX,BP { := 4-bytes_per_plane3_row }
-
- {don't save source- and destination addresses}
- MOV BX,CX {BX:=row counter }
- @eineZeile4c1:
- MOV CX,BP {CX:=bytes_per_plane0_row }
- REP MOVSB {move data of one row }
- ADD DI,AX {set DI to next destination row }
- ADD SI,DX {set SI to next tile's source addr. }
- DEC BX
- JNZ @eineZeile4c1
-
- {--- short cut has been taken: thus, reset write mode 0! }
- MOV AX,4005h
- MOV DX,3CEh
- OUT DX,AX
- {---}
- JMP @UpperRightDone
-
- @mode0c:
- MOV AH,CS:[OFFSET CS_TranslateTab +BX]
- OUT DX,AX {choose plane to write at }
- PUSH AX {and preserve it for later}
-
- MOV DX,3CEh
- MOV AX,0004h {choose read plane 0}
- OUT DX,AX
-
- MOV BX,BP
- SHR BX,1
- SHR BX,1 {BX:=bytes_per_plane0_row = (16+3-rightcut) DIV 4 }
-
- MOV AX,LINESIZE {adjustment for row target addresses }
- SUB AX,BX { := LINESIZE-bytes_per_plane0_row }
- MOV DX,4 {adjustment for source addresses of the tiles}
- SUB DX,BX { := 4-bytes_per_plane0_row }
-
- PUSH SI {save source- and destination address for other planes}
- PUSH DI
- PUSH BP {save BP }
- PUSH CX {CX = save row counter }
- MOV BP,CX {BP:=row counter }
- @eineZeile1c:
- MOV CX,BX {CX:=bytes_per_plane0_row }
- REP MOVSB {move data of one row }
- ADD DI,AX {set DI to next destination row }
- ADD SI,DX {set SI to next tile's source addr. }
- DEC BP
- JNZ @eineZeile1c
- POP CX
- POP BP
- POP DI
- POP SI
-
- MOV DX,3CEh
- MOV AX,0104h {choose read plane 1}
- OUT DX,AX
-
- MOV DX,3C4h {next write plane: }
- POP AX
- SHL AH,1
- CMP AH,16
- JNE @nowrap1c
- MOV AH,1 {plane 0 follows after plane 3 again, but}
- INC DI {the destination address has increased by 1 byte}
- @nowrap1c:
- OUT DX,AX
- PUSH AX
-
-
- DEC BP {BP:=16+2-rightcut}
- MOV BX,BP
- SHR BX,1
- SHR BX,1 {BX:=bytes_per_plane1_row }
-
- MOV AX,LINESIZE {adjustment for row target addresses }
- SUB AX,BX { := LINESIZE-bytes_per_plane1_row }
- MOV DX,4 {adjustment for source addresses of the tiles}
- SUB DX,BX { := 4-bytes_per_plane1_row }
-
- PUSH SI {save source- and destination address for other planes}
- PUSH DI
- PUSH BP {save BP }
- PUSH CX {CX = save row counter }
- MOV BP,CX {BP:=row counter }
- @eineZeile2c:
- MOV CX,BX {CX:=bytes_per_plane0_row }
- REP MOVSB {move data of one row }
- ADD DI,AX {set DI to next destination row }
- ADD SI,DX {set SI to next tile's source addr. }
- DEC BP
- JNZ @eineZeile2c
- POP CX
- POP BP
- POP DI
- POP SI
-
- MOV DX,3CEh
- MOV AX,0204h {choose read plane 2}
- OUT DX,AX
-
- MOV DX,3C4h {next write plane: }
- POP AX
- SHL AH,1
- CMP AH,16
- JNE @nowrap2c
- MOV AH,1 {plane 0 follows after plane 3 again, but}
- INC DI {the destination address has increased by 1 byte}
- @nowrap2c:
- OUT DX,AX
- PUSH AX
-
-
- DEC BP {BP:=16+1-rightcut}
- MOV BX,BP
- SHR BX,1
- SHR BX,1 {BX:=bytes_per_plane2_row }
-
- MOV AX,LINESIZE {adjustment for row target addresses }
- SUB AX,BX { := LINESIZE-bytes_per_plane2_row }
- MOV DX,4 {adjustment for source addresses of the tiles}
- SUB DX,BX { := 4-bytes_per_plane2_row }
-
- PUSH SI {save source- and destination address for other planes}
- PUSH DI
- PUSH BP {save BP }
- PUSH CX {CX = save row counter }
- MOV BP,CX {BP:=row counter }
- @eineZeile3c:
- MOV CX,BX {CX:=bytes_per_plane0_row }
- REP MOVSB {move data of one row }
- ADD DI,AX {set DI to next destination row }
- ADD SI,DX {set SI to next tile's source addr. }
- DEC BP
- JNZ @eineZeile3c
- POP CX
- POP BP
- POP DI
- POP SI
-
- MOV DX,3CEh
- MOV AX,0304h {choose read plane 3}
- OUT DX,AX
-
- MOV DX,3C4h {next write plane: }
- POP AX
- SHL AH,1
- CMP AH,16
- JNE @nowrap3c
- MOV AH,1 {plane 0 follows after plane 3 again, but}
- INC DI {the destination address has increased by 1 byte}
- @nowrap3c:
- OUT DX,AX
- {do not push value again!}
-
-
- DEC BP {BP:=16-rightcut}
- @lastplane3:
-
- SHR BP,1 {use BP directly }
- SHR BP,1 {BP:=bytes_per_plane3_row }
-
- MOV AX,LINESIZE {adjustment for row target addresses }
- SUB AX,BP { := LINESIZE-bytes_per_plane3_row }
- MOV DX,4 {adjustment for source addresses of the tiles}
- SUB DX,BP { := 4-bytes_per_plane3_row }
-
- {don't save source- and destination addresses}
- MOV BX,CX {BX:=row counter }
- @eineZeile4c:
- MOV CX,BP {CX:=bytes_per_plane0_row }
- REP MOVSB {move data of one row }
- ADD DI,AX {set DI to next destination row }
- ADD SI,DX {set SI to next tile's source addr. }
- DEC BX
- JNZ @eineZeile4c
-
- @UpperRightDone:
- POP BP
- MOV AX,SEG @Data {restore DS }
- MOV DS,AX
-
- @label1:
- MOV AX,actIndex {adjust actIndex for next tile-row: }
- STC {actIndex:=actIndex-tiles+1}
- SBB AX,tiles
- MOV actIndex,AX
-
- {Now draw all tiles which are completely onscreen }
- {(that is: all non-cut) tiles: }
- @do_innertiles:
- MOV AX,ypix
- MOV y,AX
- MOV AX,actIndex
- ADD AX,XTiles
- MOV RandIndex,AX
- INC AX
- MOV actIndex,AX
-
- @repeat2:
- MOV AX,ytil
- MOV CL,1
- OR AX,AX
- JS @go4
- CMP AX,YTiles
- JAE @go4
- DEC CL
- @go4:
- MOV offscreenFlag,CL
- MOV AX,xpix
- MOV x,AX
- MOV AX,offsetXTiles
- MOV xtil,AX
-
- @repeat3:
- MOV CL,offscreenFlag
- XOR SI,SI
- DEC CL
- JZ @go5
- OR AX,AX
- JS @go5
- CMP AX,XTiles
- JAE @go5
- MOV SI,actIndex
- @go5:
-
-
- {PROCEDURE DrawInnerTile(x,y:INTEGER; index:WORD);}
- { in: (x,y) = upper left corner of the tile to be drawn,}
- { SI = index = tile number}
- {out: tile has been drawn on actual page PAGEADR }
- {rem: tile must be completely onscreen, there will be }
- { no check for that }
- MOV AH,[OFFSET BackTile +SI] {AH:=BackTile[index]}
- XOR AL,AL
-
- SHR AH,1 {AX:=tile*64 =tile SHL 6 =(tile SHL 8) SHR 2 }
- RCR AL,1 {therefore: set AH:=tile and afterwards, shift AX }
- SHR AH,1 {2 bits to the right!}
- RCR AL,1
- MOV SI,AX {That's also the offset part of the source ad. in page3}
-
- MOV DI,y {the first destination addr. is DI:=y*LINESIZE+(x div 4)}
- SHL DI,1
- MOV DI,CS:[OFFSET GADR + DI]
- MOV AX,x
- MOV BX,AX {have a copy of X in BX }
- SHR AX,1
- SHR AX,1
- ADD DI,AX
-
- MOV ES,PAGEADR {(segment part of) dest. address is active page}
- MOV DS,SCROLLADR {(segment part of) source addr. is page SCROLLPAGE}
-
- MOV DX,3C4h
- MOV AL,2
- AND BX,3 {BX:=1st write plane (1st READ plane=0!) }
- JNE @mode0d {only if x mod 4=0 is it possible to use WriteMode1 }
-
- {--- short-cut possible, using write mode1 }
- MOV AH,0Fh {work on all 4 planes simultaneously }
- OUT DX,AX
- MOV AX,4105h
- MOV DX,3CEh
- OUT DX,AX {choose write mode 1}
- MOV BX,4
-
- MOV AX,LINESIZE-4
- MOV BX,4 {16 pixels = 4 bytes}
- MOV CX,BX {no "MOVSW", as we use write mode1}
- REP MOVSB {draw 1st row }
- ADD DI,AX {set DI to next row }
- MOV CX,BX
- REP MOVSB {2.row }
- ADD DI,AX
- MOV CX,BX
- REP MOVSB {3.row }
- ADD DI,AX
- MOV CX,BX
- REP MOVSB {4.row }
- ADD DI,AX
- MOV CX,BX
- REP MOVSB {5.row }
- ADD DI,AX
- MOV CX,BX
- REP MOVSB {6.row }
- ADD DI,AX
- MOV CX,BX
- REP MOVSB {7.row }
- ADD DI,AX
- MOV CX,BX
- REP MOVSB {8.row }
- ADD DI,AX
- MOV CX,BX
- REP MOVSB {9.row }
- ADD DI,AX
- MOV CX,BX
- REP MOVSB {10.row }
- ADD DI,AX
- MOV CX,BX
- REP MOVSB {11.row }
- ADD DI,AX
- MOV CX,BX
- REP MOVSB {12.row }
- ADD DI,AX
- MOV CX,BX
- REP MOVSB {13.row }
- ADD DI,AX
- MOV CX,BX
- REP MOVSB {14.row }
- ADD DI,AX
- MOV CX,BX
- REP MOVSB {15.row }
- ADD DI,AX
- MOV CX,BX
- REP MOVSB {16.row }
-
-
- {--- short cut has been taken: thus, reset write mode 0! }
- MOV AX,4005h
- MOV DX,3CEh
- OUT DX,AX
- {---}
- JMP @InnerTileDone
-
- @mode0d:
- MOV AH,CS:[OFFSET CS_TranslateTab+BX]
- OUT DX,AX
- PUSH AX {save actual write plane }
-
- MOV DX,3CEh
- MOV AX,0004h {choose plane 0 for reading }
- OUT DX,AX
-
- MOV AX,LINESIZE-4 {adjustment for row addresses }
-
- MOVSW {16 horizontal pixels = 4 bytes per line }
- MOVSW {draw 1st row }
- ADD DI,AX {set DI to next row }
- MOVSW {2.row }
- MOVSW
- ADD DI,AX
- MOVSW
- MOVSW {3.row }
- ADD DI,AX
- MOVSW
- MOVSW {4.row }
- ADD DI,AX
- MOVSW
- MOVSW {5.row }
- ADD DI,AX
- MOVSW
- MOVSW {6.row }
- ADD DI,AX
- MOVSW
- MOVSW {7.row }
- ADD DI,AX
- MOVSW
- MOVSW {8.row }
- ADD DI,AX
- MOVSW
- MOVSW {9.row }
- ADD DI,AX
- MOVSW
- MOVSW {10.row }
- ADD DI,AX
- MOVSW
- MOVSW {11.row }
- ADD DI,AX
- MOVSW
- MOVSW {12.row }
- ADD DI,AX
- MOVSW
- MOVSW {13.row }
- ADD DI,AX
- MOVSW
- MOVSW {14.row }
- ADD DI,AX
- MOVSW
- MOVSW {15.row }
- ADD DI,AX
- MOVSW
- MOVSW {16.row }
- ADD DI,AX
-
- MOV AX,0104h {DX=3CEh -> choose read plane 1}
- OUT DX,AX
-
- MOV DX,3C4h {next write plane: }
- POP AX
- SHL AH,1
- CMP AH,16
- JNE @nowrap1d
- MOV AH,1 {plane 0 follows after plane 3 again, but}
- INC DI {the destination address has increased by 1 byte}
- @nowrap1d:
- OUT DX,AX
- PUSH AX
- SUB DI,16*LINESIZE {reset DI to the source address }
- SUB SI,16*4 {SI, too}
-
-
- MOV AX,LINESIZE-4
- MOVSW
- MOVSW {draw 1st row }
- ADD DI,AX {set DI to next row }
- MOVSW
- MOVSW {2.row }
- ADD DI,AX
- MOVSW
- MOVSW {3.row }
- ADD DI,AX
- MOVSW
- MOVSW {4.row }
- ADD DI,AX
- MOVSW
- MOVSW {5.row }
- ADD DI,AX
- MOVSW
- MOVSW {6.row }
- ADD DI,AX
- MOVSW
- MOVSW {7.row }
- ADD DI,AX
- MOVSW
- MOVSW {8.row }
- ADD DI,AX
- MOVSW
- MOVSW {9.row }
- ADD DI,AX
- MOVSW
- MOVSW {10.row }
- ADD DI,AX
- MOVSW
- MOVSW {11.row }
- ADD DI,AX
- MOVSW
- MOVSW {12.row }
- ADD DI,AX
- MOVSW
- MOVSW {13.row }
- ADD DI,AX
- MOVSW
- MOVSW {14.row }
- ADD DI,AX
- MOVSW
- MOVSW {15.row }
- ADD DI,AX
- MOVSW
- MOVSW {16.row }
- ADD DI,AX
-
- POP AX
- SHL AH,1
- CMP AH,16
- JNE @nowrap2d
- MOV AH,1 {plane 0 follows after plane 3 again, but}
- INC DI {the destination address has increased by 1 byte}
- @nowrap2d:
- OUT DX,AX {DX=3C4h -> set write plane }
- PUSH AX
- MOV DX,3CEh
- MOV AX,0204h {set read plane 2 }
- OUT DX,AX
- SUB DI,16*LINESIZE
- SUB SI,16*4
-
-
- MOV AX,LINESIZE-4
- MOVSW
- MOVSW {draw 1st row }
- ADD DI,AX {set DI to next row }
- MOVSW
- MOVSW {2.row }
- ADD DI,AX
- MOVSW
- MOVSW {3.row }
- ADD DI,AX
- MOVSW
- MOVSW {4.row }
- ADD DI,AX
- MOVSW
- MOVSW {5.row }
- ADD DI,AX
- MOVSW
- MOVSW {6.row }
- ADD DI,AX
- MOVSW
- MOVSW {7.row }
- ADD DI,AX
- MOVSW
- MOVSW {8.row }
- ADD DI,AX
- MOVSW
- MOVSW {9.row }
- ADD DI,AX
- MOVSW
- MOVSW {10.row }
- ADD DI,AX
- MOVSW
- MOVSW {11.row }
- ADD DI,AX
- MOVSW
- MOVSW {12.row }
- ADD DI,AX
- MOVSW
- MOVSW {13.row }
- ADD DI,AX
- MOVSW
- MOVSW {14.row }
- ADD DI,AX
- MOVSW
- MOVSW {15.row }
- ADD DI,AX
- MOVSW
- MOVSW {16.row }
- ADD DI,AX
-
- MOV AX,0304h
- OUT DX,AX {DX=3CEh -> choose read plane 3}
- MOV DX,3C4h
- POP AX
- SHL AH,1
- CMP AH,16
- JNE @nowrap3d
- MOV AH,1 {plane 0 follows after plane 3 again, but}
- INC DI {the destination address has increased by 1 byte}
- @nowrap3d:
- OUT DX,AX {DX=3C4h -> set write plane }
- SUB DI,16*LINESIZE
- SUB SI,16*4
-
-
- @lastPlane4:
- MOV AX,LINESIZE-4
- MOVSW
- MOVSW {draw 1st row }
- ADD DI,AX {set DI to next row }
- MOVSW
- MOVSW {2.row }
- ADD DI,AX
- MOVSW
- MOVSW {3.row }
- ADD DI,AX
- MOVSW
- MOVSW {4.row }
- ADD DI,AX
- MOVSW
- MOVSW {5.row }
- ADD DI,AX
- MOVSW
- MOVSW {6.row }
- ADD DI,AX
- MOVSW
- MOVSW {7.row }
- ADD DI,AX
- MOVSW
- MOVSW {8.row }
- ADD DI,AX
- MOVSW
- MOVSW {9.row }
- ADD DI,AX
- MOVSW
- MOVSW {10.row }
- ADD DI,AX
- MOVSW
- MOVSW {11.row }
- ADD DI,AX
- MOVSW
- MOVSW {12.row }
- ADD DI,AX
- MOVSW
- MOVSW {13.row }
- ADD DI,AX
- MOVSW
- MOVSW {14.row }
- ADD DI,AX
- MOVSW
- MOVSW {15.row }
- ADD DI,AX
- MOVSW
- MOVSW {16.row }
-
-
- @InnerTileDone:
- MOV AX,SEG @Data {restore DS }
- MOV DS,AX
-
- INC actIndex
- MOV AX,xtil
- INC AX
- MOV xtil,AX
- MOV DX,x
- ADD DX,16
- MOV x,DX
- CMP DX,XMAX+1-16
- JBE @repeat3
-
- INC ytil
- MOV AX,actIndex
- SUB AX,tiles
- ADD AX,XTiles
- MOV actIndex,AX
- MOV AX,y
- ADD AX,16
- MOV y,AX
- CMP AX,YMAX+1-16
- JBE @repeat2
-
- {Now draw the lower right tile - if it doesn't have been drawn by one of}
- {routines above: }
- CMP bottomcut,0
- JE @do_raender
- MOV DX,offsetXTiles
- MOV xt,DX
- MOV AX,ytil
- MOV yt,AX
- MOV CL,1
- OR AX,AX
- JS @go6
- CMP AX,YTiles
- JAE @go6
- DEC CL
- @go6:
- MOV offscreenFlag,CL
- CMP leftcut,0
- JE @label2
- XOR SI,SI
- DEC CL
- JZ @go7
- DEC DX {DX=xt-1}
- JS @go7
- CMP DX,XTiles
- JAE @go7
- MOV SI,actIndex
- DEC SI
- @go7:
-
- {PROCEDURE DrawLowerLeftTile(y,leftcut,bottomcut:INTEGER; index:WORD);}
- { in: (0,y) = upper left corner of the tile to be drawn}
- { leftcut = number of left tile-columns to be cut off }
- { bottomcut = dto., bottom}
- { SI = index = tile number}
- {out: tile has been drawn on actual page PAGEADR }
- {rem: tile has been clipped at its left and bottom accordingly}
- { leftcut must lie in the range 0..15, 16 is allowed (but senseless) }
- { bottomcut must lie in the range 0..15, 16 is not allowed}
- { bottomcut could also be computed by: }
- { bottomcut:=y+15-ymax}
- MOV AH,[OFFSET BackTile +SI] {AH:=BackTile[index]}
- XOR AL,AL
-
- SHR AH,1 {AX:=tile*64 =tile SHL 6 =(tile SHL 8) SHR 2 }
- RCR AL,1 {therefore: set AH:=tile and afterwards, shift AX }
- SHR AH,1 {2 bits to the right!}
- RCR AL,1
- MOV SI,AX {That's also the offset part of the source ad. in page3}
-
- MOV DI,y {first dest. addr. is DI:=y*LINESIZE+(0 div 4)=y*LINESIZE }
- SHL DI,1
- MOV DI,CS:[OFFSET GADR + DI]
-
- MOV AX,leftcut
- MOV BX,AX {have a copy of leftcut in BX }
- SHR AX,1
- SHR AX,1
- ADD SI,AX {increment SI by cutoff (=leftcut div 4) bytes }
-
- MOV CX,16
- SUB CX,bottomcut {CX:=16-bottomcut = rows to draw }
-
- {Now there is no further variable on stack, so BP can be used }
- {for other purposes!}
- PUSH BP {will be needed when leaving the procedure! }
- MOV BP,16+3
- SUB BP,BX {BP:=16+3-leftcut, because the number of bytes per row }
- {of plane i is computed by (16+3-i-leftcut) SHR 2 }
-
-
- MOV ES,PAGEADR {(segment part of) dest. address is active page}
- MOV DS,SCROLLADR {(segment part of) source addr. is page SCROLLPAGE}
-
- MOV DX,3CEh
- AND BL,3
- MOV AH,BL {AH:=leftcut mod 4}
- MOV AL,4
-
- JNE @mode0e {only if leftcut mod 4=0 is it possible to use WriteMode1 }
-
- {--- short-cut possible, using write mode1: DX=3CEh, BP=16+3-leftcut }
- { BP being "3 units to big" doesn't matter, because this code will }
- { only be run if leftcut mod 4=0, thus 16+3-leftcut=...11b, the }
- { "11b" will be cut off while shifting right, anyway! }
- MOV AX,4105h
- OUT DX,AX {choose write mode 1}
- MOV DX,3C4h
- MOV AX,0F02h {work on all 4 planes simultaneously }
- OUT DX,AX
-
- SHR BP,1 {use BP directly }
- SHR BP,1 {BP:=bytes_per_plane3_row }
-
- MOV AX,LINESIZE {adjustment for row target addresses }
- SUB AX,BP { := LINESIZE-bytes_per_plane3_row }
- MOV DX,4 {adjustment for source addresses of the tiles}
- SUB DX,BP { := 4-bytes_per_plane3_row }
-
- MOV BX,CX {BX:=row counter }
- @eineZeile4d1:
- MOV CX,BP {CX:=bytes_per_plane0_row }
- REP MOVSB {move data of one row }
- ADD DI,AX {set DI to next destination row }
- ADD SI,DX {set SI to next tile's source addr. }
- DEC BX
- JNZ @eineZeile4d1
-
- {--- short cut has been taken: thus, reset write mode 0! }
- MOV AX,4005h
- MOV DX,3CEh
- OUT DX,AX
- {---}
- JMP @LowerLeftTileDone
-
- @mode0e:
- OUT DX,AX {choose plane from which to read}
- PUSH AX {and preserve it for later}
-
- MOV DX,3C4h
- MOV AX,0102h {choose write plane 0 }
- OUT DX,AX
-
- MOV BX,BP
- SHR BX,1
- SHR BX,1 {BX:=bytes_per_plane0_row = (16+3-leftcut) DIV 4 }
-
- MOV AX,LINESIZE {adjustment for row target addresses }
- SUB AX,BX { := LINESIZE-bytes_per_plane0_row }
- MOV DX,4 {adjustment for source addresses of the tiles}
- SUB DX,BX { := 4-bytes_per_plane0_row }
-
- PUSH SI {save source- and destination address for other planes}
- PUSH DI
- PUSH BP {save BP }
- PUSH CX {CX = save row counter }
- MOV BP,CX {BP:=row counter }
- @eineZeile1d:
- MOV CX,BX {CX:=bytes_per_plane0_row }
- REP MOVSB {move data of one row }
- ADD DI,AX {set DI to next destination row }
- ADD SI,DX {set SI to next tile's source addr. }
- DEC BP
- JNZ @eineZeile1d
- POP CX
- POP BP
- POP DI
- POP SI
-
- MOV DX,3C4h
- MOV AX,0202h {choose write plane 1 }
- OUT DX,AX
-
- MOV DX,3CEh {next read plane: }
- POP AX
- INC AH
- AND AH,3 {increment by 1 MOD 4}
- JNE @nowrap1e
- INC SI {plane 0 follows after plane 3 again, but}
- {the source address has increased by 1 byte }
- @nowrap1e:
- OUT DX,AX
- PUSH AX
-
-
- DEC BP {BP:=16+2-leftcut}
- MOV BX,BP
- SHR BX,1
- SHR BX,1 {BX:=bytes_per_plane1_row }
-
- MOV AX,LINESIZE {adjustment for row target addresses }
- SUB AX,BX { := LINESIZE-bytes_per_plane1_row }
- MOV DX,4 {adjustment for source addresses of the tiles}
- SUB DX,BX { := 4-bytes_per_plane1_row }
-
- PUSH SI {save source- and destination address for other planes}
- PUSH DI
- PUSH BP {save BP }
- PUSH CX {CX = save row counter }
- MOV BP,CX {BP:=row counter }
- @eineZeile2d:
- MOV CX,BX {CX:=bytes_per_plane0_row }
- REP MOVSB {move data of one row }
- ADD DI,AX {set DI to next destination row }
- ADD SI,DX {set SI to next tile's source addr. }
- DEC BP
- JNZ @eineZeile2d
- POP CX
- POP BP
- POP DI
- POP SI
-
- MOV DX,3C4h
- MOV AX,0402h {choose write plane 2 }
- OUT DX,AX
-
- MOV DX,3CEh {next read plane: }
- POP AX
- INC AH
- AND AH,3 {increment by 1 MOD 4}
- JNE @nowrap2e
- INC SI {plane 0 follows after plane 3 again, but}
- {the source address has increased by 1 byte }
- @nowrap2e:
- OUT DX,AX
- PUSH AX
-
-
- DEC BP {BP:=16+1-leftcut}
- MOV BX,BP
- SHR BX,1
- SHR BX,1 {BX:=bytes_per_plane2_row }
-
- MOV AX,LINESIZE {adjustment for row target addresses }
- SUB AX,BX { := LINESIZE-bytes_per_plane2_row }
- MOV DX,4 {adjustment for source addresses of the tiles}
- SUB DX,BX { := 4-bytes_per_plane2_row }
-
- PUSH SI {save source- and destination address for other planes}
- PUSH DI
- PUSH BP {save BP }
- PUSH CX {CX = save row counter }
- MOV BP,CX {BP:=row counter }
- @eineZeile3d:
- MOV CX,BX {CX:=bytes_per_plane0_row }
- REP MOVSB {move data of one row }
- ADD DI,AX {set DI to next destination row }
- ADD SI,DX {set SI to next tile's source addr. }
- DEC BP
- JNZ @eineZeile3d
- POP CX
- POP BP
- POP DI
- POP SI
-
- MOV DX,3C4h
- MOV AX,0802h {choose write plane 3 }
- OUT DX,AX
-
- MOV DX,3CEh {next read plane: }
- POP AX
- INC AH
- AND AH,3 {increment by 1 MOD 4}
- JNE @nowrap3e
- INC SI {plane 0 follows after plane 3 again, but}
- {the source address has increased by 1 byte }
- @nowrap3e:
- OUT DX,AX
- {do not push value again!}
-
-
- DEC BP {BP:=16-leftcut}
- @lastplane5:
-
- SHR BP,1 {use BP directly }
- SHR BP,1 {BP:=bytes_per_plane3_row }
-
- MOV AX,LINESIZE {adjustment for row target addresses }
- SUB AX,BP { := LINESIZE-bytes_per_plane3_row }
- MOV DX,4 {adjustment for source addresses of the tiles}
- SUB DX,BP { := 4-bytes_per_plane3_row }
-
- MOV BX,CX {BX:=row counter }
- @eineZeile4d:
- MOV CX,BP {CX:=bytes_per_plane0_row }
- REP MOVSB {move data of one row }
- ADD DI,AX {set DI to next destination row }
- ADD SI,DX {set SI to next tile's source addr. }
- DEC BX
- JNZ @eineZeile4d
-
- @LowerLeftTileDone:
- POP BP
- MOV AX,SEG @Data {restore DS }
- MOV DS,AX
-
- @label2:
- MOV AX,xpix
- MOV x,AX
-
- {Now the lower tiles, which are not partially cut at their left or right:}
- @repeat4:
- MOV CL,offscreenFlag
- XOR SI,SI
- DEC CL
- JZ @go8
- MOV AX,xt
- OR AX,AX
- JS @go8
- CMP AX,XTiles
- JAE @go8
- MOV SI,actIndex
- @go8:
-
- {PROCEDURE DrawLowerTile(x,y,bottomcut:INTEGER; index:WORD);}
- { in: (x,y) = upper left corner of the tile to be drawn}
- { bottomcut = number of bottom tile-rows to be cut off }
- { SI = index = tile number}
- {out: tile has been drawn on actual page PAGEADR }
- {rem: tile has been clipped at its bottom accordingly}
- { bottomcut must lie in the range 0..15, 16 is not allowed!}
- { bottomcut could also be computed by: }
- { bottomcut:=y+15-ymax}
- MOV AH,[OFFSET BackTile +SI] {AH:=BackTile[index]}
- XOR AL,AL
-
- SHR AH,1 {AX:=tile*64 =tile SHL 6 =(tile SHL 8) SHR 2 }
- RCR AL,1 {therefore: set AH:=tile and afterwards, shift AX }
- SHR AH,1 {2 bits to the right!}
- RCR AL,1
- MOV SI,AX {That's also the offset part of the source ad. in page3}
-
- MOV DI,y {the first destination addr. is DI:=y*LINESIZE+(x div 4)}
- SHL DI,1
- MOV DI,CS:[OFFSET GADR + DI]
- MOV AX,x
- MOV BX,AX {have a copy of X in BX }
- SHR AX,1
- SHR AX,1
- ADD DI,AX
-
- MOV CX,16
- SUB CX,bottomcut {CX:=number of rows to draw = 16-bottomcut }
-
- {Now there is no further variable on stack, so BP can be used }
- {for other purposes!}
- PUSH BP {will be needed when leaving the procedure! }
- MOV BP,CX
- SHL BP,1
- SHL BP,1 {BP := (rows to draw)*4 }
-
- MOV ES,PAGEADR {(segment part of) dest. address is active page}
- MOV DS,SCROLLADR {(segment part of) source addr. is page SCROLLPAGE}
-
- MOV DX,3C4h
- MOV AL,2
- AND BX,3 {BX:=1st write plane (1st READ plane=0!) }
- JNE @mode0f {only if x mod 4=0 is it possible to use WriteMode1 }
-
- {--- short-cut possible, using write mode1 }
- MOV AH,0Fh {work on all 4 planes simultaneously }
- OUT DX,AX
- MOV AX,4105h
- MOV DX,3CEh
- OUT DX,AX {choose write mode 1}
- MOV BX,CX {BX:=CX=rows to draw }
-
- MOV AX,LINESIZE-4
- MOV CX,BX {CX:=number of rows to draw }
- @eineZeile4e1:
- MOVSB {no "MOVSW", as we use write mode1}
- MOVSB
- MOVSB
- MOVSB
- ADD DI,AX {set DI to next row }
- LOOP @eineZeile4e1
-
- {--- short cut has been taken: thus, reset write mode 0! }
- MOV AX,4005h
- MOV DX,3CEh
- OUT DX,AX
- {---}
- JMP @LowerTileDone
-
- @mode0f:
- MOV AH,CS:[OFFSET CS_TranslateTab+BX]
- OUT DX,AX
- PUSH AX {save actual write plane }
-
- MOV DX,3CEh
- MOV AX,0004h {choose plane 0 for reading }
- OUT DX,AX
-
- MOV AX,LINESIZE-4 {adjustment for row addresses }
- MOV BX,CX {save number of rows to draw into BX }
- @eineZeile1e:
- MOVSW
- MOVSW
- ADD DI,AX {set DI to next row }
- LOOP @eineZeile1e
-
- MOV AX,0104h {DX=3CEh -> choose read plane 1}
- OUT DX,AX
-
- MOV DX,3C4h {next write plane: }
- POP AX
- SHL AH,1
- CMP AH,16
- JNE @nowrap1f
- MOV AH,1 {plane 0 follows after plane 3 again, but}
- INC DI {the destination address has increased by 1 byte}
- @nowrap1f:
- OUT DX,AX
- PUSH AX
- SHL BX,1 {reset DI to the source address: }
- SUB DI,CS:[OFFSET GADR + BX] {thus, decrement DI by (rows to draw)* }
- SHR BX,1 {LINESIZE (N.B.: BX=number of rows to draw)}
- SUB SI,BP {reset SI, too }
-
-
- MOV AX,LINESIZE-4
- MOV CX,BX {CX:=number of rows to draw }
- @eineZeile2e:
- MOVSW
- MOVSW
- ADD DI,AX {set DI to next row }
- LOOP @eineZeile2e
-
- POP AX
- SHL AH,1
- CMP AH,16
- JNE @nowrap2f
- MOV AH,1 {plane 0 follows after plane 3 again, but}
- INC DI {the destination address has increased by 1 byte}
- @nowrap2f:
- OUT DX,AX {DX=3C4h -> set write plane }
- PUSH AX
- MOV DX,3CEh
- MOV AX,0204h {set read plane 2 }
- OUT DX,AX
- SHL BX,1 {reset DI to the source address: }
- SUB DI,CS:[OFFSET GADR + BX] {thus, decrement DI by (rows to draw)* }
- SHR BX,1 {LINESIZE (N.B.: BX=number of rows to draw)}
- SUB SI,BP {reset SI, too }
-
-
- MOV AX,LINESIZE-4
- MOV CX,BX {CX:=number of rows to draw }
- @eineZeile3e:
- MOVSW
- MOVSW
- ADD DI,AX {set DI to next row }
- LOOP @eineZeile3e
-
- MOV AX,0304h
- OUT DX,AX {DX=3CEh -> choose read plane 3}
- MOV DX,3C4h
- POP AX
- SHL AH,1
- CMP AH,16
- JNE @nowrap3f
- MOV AH,1 {plane 0 follows after plane 3 again, but}
- INC DI {the destination address has increased by 1 byte}
- @nowrap3f:
- OUT DX,AX {DX=3C4h -> set write plane }
- SHL BX,1 {reset DI to the source address: }
- SUB DI,CS:[OFFSET GADR + BX] {thus, decrement DI by (rows to draw)* }
- SHR BX,1 {LINESIZE (N.B.: BX=number of rows to draw)}
- SUB SI,BP {reset SI, too }
-
-
- @lastPlane6:
- MOV AX,LINESIZE-4
- MOV CX,BX {CX:=number of rows to draw }
- @eineZeile4e:
- MOVSW
- MOVSW
- ADD DI,AX {set DI to next row }
- LOOP @eineZeile4e
-
- @LowerTileDone:
- POP BP
- MOV AX,SEG @Data {restore DS }
- MOV DS,AX
-
- INC xt
- INC actIndex
- MOV AX,x
- ADD AX,16
- MOV x,AX
- CMP AX,XMAX+1-16
- JBE @repeat4
-
- {Now evtl. the lower right corner-tile remains to be drawn:}
- CMP AX,XMAX+1
- JE @do_raender
- MOV CL,offscreenFlag
- XOR SI,SI
- DEC CL
- JZ @go9
- MOV AX,xt
- OR AX,AX
- JS @go9
- CMP AX,XTiles
- JAE @go9
- MOV SI,actIndex
- @go9:
-
- {PROCEDURE DrawLowerRightTile(x,y,rightcut,bottomcut:INTEGER; index:WORD);}
- { in: (x,y) = upper left corner of the tile to be drawn}
- { rightcut = number of right tile-columns to be cut off }
- { bottomcut = dto., bottom}
- { bottomcut must lie in the range 0..15, 16 is not allowed}
- { bottomcut could also be computed by: }
- { bottomcut:=y+15-ymax}
- { SI = index = tile number}
- {out: tile has been drawn on actual page PAGEADR }
- {rem: tile has been clipped at its right and bottom accordingly}
- { rightcut must lie between 0..15, 16 is allowed (but senseless)! }
- { rightcut could also be computed (for x>xmax-16) by }
- { rightcut := x+15-xmax }
- { bottomcut must lie in the range 0..15, 16 is not allowed}
- { bottomcut could also be computed by: }
- { bottomcut:=y+15-ymax}
- MOV AH,[OFFSET BackTile +SI] {AH:=BackTile[index]}
- XOR AL,AL
-
- SHR AH,1 {AX:=tile*64 =tile SHL 6 =(tile SHL 8) SHR 2 }
- RCR AL,1 {therefore: set AH:=tile and afterwards, shift AX }
- SHR AH,1 {2 bits to the right!}
- RCR AL,1
- MOV SI,AX {That's also the offset part of the source ad. in page3}
-
- MOV DI,y {the first destination addr. is DI:=y*LINESIZE+(x div 4)}
- SHL DI,1
- MOV DI,CS:[OFFSET GADR + DI]
- MOV AX,x
- MOV BX,AX {place a copy of x in BX}
- SHR AX,1
- SHR AX,1
- ADD DI,AX
-
- MOV AX,rightcut
- MOV CX,16
- SUB CX,bottomcut {CX:=16-bottomcut = rows to draw }
-
- {Now there is no further variable on stack, so BP can be used }
- {for other purposes!}
- PUSH BP {will be needed when leaving the procedure! }
- MOV BP,16+3
- SUB BP,AX {BP:=16+3-rightcut, because the number of bytes per row }
- {of plane i is computed by (16+3-i-rightcut) SHR 2 }
- MOV AH,AL {save rightcut to AH }
-
-
- MOV ES,PAGEADR {(segment part of) dest. address is active page}
- MOV DS,SCROLLADR {(segment part of) source addr. is page SCROLLPAGE}
-
- MOV DX,3C4h
- MOV AL,2
- AND BX,3
-
- JNE @mode0g {only if x mod 4=0 _and_ rightcut mod 4=0, then we can }
- AND AH,3 {use write mode 1! }
- JNE @mode0g
-
- {--- short-cut possible, using write mode1: DX=3C4h, BP=16+3-rightcut }
- MOV AH,0Fh
- OUT DX,AX {work on all 4 planes simultaneously }
- MOV DX,3CEh
- MOV AX,4105h {choose write mode 1}
- OUT DX,AX
- SUB BP,3 {set BP to proper size }
-
- SHR BP,1 {use BP directly }
- SHR BP,1 {BX:=bytes_per_plane3_row }
-
- MOV AX,LINESIZE {adjustment for row target addresses }
- SUB AX,BP { := LINESIZE-bytes_per_plane3_row }
- MOV DX,4 {adjustment for source addresses of the tiles}
- SUB DX,BP { := 4-bytes_per_plane3_row }
-
- MOV BX,CX {BX:=row counter }
- @eineZeile4g1:
- MOV CX,BP {CX:=bytes_per_plane0_row }
- REP MOVSB {move data of one row }
- ADD DI,AX {set DI to next destination row }
- ADD SI,DX {set SI to next tile's source addr. }
- DEC BX
- JNZ @eineZeile4g1
-
- {--- short cut has been taken: thus, reset write mode 0! }
- MOV AX,4005h
- MOV DX,3CEh
- OUT DX,AX
- {---}
- JMP @LowerRightTileDone
-
- @mode0g:
- MOV AH,CS:[OFFSET CS_TranslateTab +BX]
- OUT DX,AX {choose plane to write at }
- PUSH AX {and preserve it for later}
-
- MOV DX,3CEh
- MOV AX,0004h {choose read plane 0}
- OUT DX,AX
-
- MOV BX,BP
- SHR BX,1
- SHR BX,1 {BX:=bytes_per_plane0_row = (16+3-rightcut) DIV 4 }
-
- MOV AX,LINESIZE {adjustment for row target addresses }
- SUB AX,BX { := LINESIZE-bytes_per_plane0_row }
- MOV DX,4 {adjustment for source addresses of the tiles}
- SUB DX,BX { := 4-bytes_per_plane0_row }
-
- PUSH SI {save source- and destination address for other planes}
- PUSH DI
- PUSH BP {save BP }
- PUSH CX {CX = save row counter }
- MOV BP,CX {BP:=row counter }
- @eineZeile1f:
- MOV CX,BX {CX:=bytes_per_plane0_row }
- REP MOVSB {move data of one row }
- ADD DI,AX {set DI to next destination row }
- ADD SI,DX {set SI to next tile's source addr. }
- DEC BP
- JNZ @eineZeile1f
- POP CX
- POP BP
- POP DI
- POP SI
-
-
- MOV DX,3CEh
- MOV AX,0104h {choose read plane 1}
- OUT DX,AX
-
- MOV DX,3C4h {next write plane: }
- POP AX
- SHL AH,1
- CMP AH,16
- JNE @nowrap1g
- MOV AH,1 {plane 0 follows after plane 3 again, but}
- INC DI {the destination address has increased by 1 byte}
- @nowrap1g:
- OUT DX,AX
- PUSH AX
-
-
- DEC BP {BP:=16+2-rightcut}
- MOV BX,BP
- SHR BX,1
- SHR BX,1 {BX:=bytes_per_plane1_row }
-
- MOV AX,LINESIZE {adjustment for row target addresses }
- SUB AX,BX { := LINESIZE-bytes_per_plane1_row }
- MOV DX,4 {adjustment for source addresses of the tiles}
- SUB DX,BX { := 4-bytes_per_plane1_row }
-
- PUSH SI {save source- and destination address for other planes}
- PUSH DI
- PUSH BP {save BP }
- PUSH CX {CX = save row counter }
- MOV BP,CX {BP:=row counter }
- @eineZeile2f:
- MOV CX,BX {CX:=bytes_per_plane0_row }
- REP MOVSB {move data of one row }
- ADD DI,AX {set DI to next destination row }
- ADD SI,DX {set SI to next tile's source addr. }
- DEC BP
- JNZ @eineZeile2f
- POP CX
- POP BP
- POP DI
- POP SI
-
-
- MOV DX,3CEh
- MOV AX,0204h {choose read plane 2}
- OUT DX,AX
-
- MOV DX,3C4h {next write plane: }
- POP AX
- SHL AH,1
- CMP AH,16
- JNE @nowrap2g
- MOV AH,1 {plane 0 follows after plane 3 again, but}
- INC DI {the destination address has increased by 1 byte}
- @nowrap2g:
- OUT DX,AX
- PUSH AX
-
-
- DEC BP {BP:=16+1-rightcut}
- MOV BX,BP
- SHR BX,1
- SHR BX,1 {BX:=bytes_per_plane2_row }
-
- MOV AX,LINESIZE {adjustment for row target addresses }
- SUB AX,BX { := LINESIZE-bytes_per_plane2_row }
- MOV DX,4 {adjustment for source addresses of the tiles}
- SUB DX,BX { := 4-bytes_per_plane2_row }
-
- PUSH SI {save source- and destination address for other planes}
- PUSH DI
- PUSH BP {save BP }
- PUSH CX {CX = save row counter }
- MOV BP,CX {BP:=row counter }
- @eineZeile3f:
- MOV CX,BX {CX:=bytes_per_plane0_row }
- REP MOVSB {move data of one row }
- ADD DI,AX {set DI to next destination row }
- ADD SI,DX {set SI to next tile's source addr. }
- DEC BP
- JNZ @eineZeile3f
- POP CX
- POP BP
- POP DI
- POP SI
-
-
- MOV DX,3CEh
- MOV AX,0304h {choose read plane 3}
- OUT DX,AX
-
- MOV DX,3C4h {next write plane: }
- POP AX
- SHL AH,1
- CMP AH,16
- JNE @nowrap3g
- MOV AH,1 {plane 0 follows after plane 3 again, but}
- INC DI {the destination address has increased by 1 byte}
- @nowrap3g:
- OUT DX,AX
- {do not push value again!}
-
-
- DEC BP {BP:=16-rightcut}
- @lastplane7:
-
- SHR BP,1 {use BP directly }
- SHR BP,1 {BX:=bytes_per_plane3_row }
-
- MOV AX,LINESIZE {adjustment for row target addresses }
- SUB AX,BP { := LINESIZE-bytes_per_plane3_row }
- MOV DX,4 {adjustment for source addresses of the tiles}
- SUB DX,BP { := 4-bytes_per_plane3_row }
-
- MOV BX,CX {BX:=row counter }
- @eineZeile4g:
- MOV CX,BP {CX:=bytes_per_plane0_row }
- REP MOVSB {move data of one row }
- ADD DI,AX {set DI to next destination row }
- ADD SI,DX {set SI to next tile's source addr. }
- DEC BX
- JNZ @eineZeile4g
-
- @LowerRightTileDone:
- POP BP
- MOV AX,SEG @Data {restore DS }
- MOV DS,AX
-
- {Now work on the tiles at the left and/or right edge of the screen: }
- @do_raender:
- CMP leftcut,0 {or "rightcut": because 320 is dividable by 16, }
- JE @ende {leftcut=0 is equivalent to rightcut=0 }
-
- MOV AX,offsetXTiles
- DEC AX
- MOV xt,AX
- MOV AX,ypix
- MOV y,AX
- INC tiles
- MOV AX,offsetYTiles
- MOV yt,AX
-
- @repeat5:
- MOV CL,1
- OR AX,AX
- JS @go10
- CMP AX,YTiles
- JAE @go10
- DEC CL
- @go10:
- MOV offscreenFlag,CL
- XOR SI,SI
- DEC CL
- JZ @go11
- MOV AX,xt
- OR AX,AX
- JS @go11
- CMP AX,XTiles
- JAE @go11
- MOV SI,RandIndex
- @go11:
-
-
- {PROCEDURE DrawLeftTile(y,leftcut:INTEGER; index:WORD);}
- { in: (0,y) = upper left corner of the tile to be drawn}
- { leftcut = number of left tile-columns to be cut off }
- { SI = index = tile number}
- {out: tile has been drawn on actual page PAGEADR }
- {rem: tile has been clipped at its left accordingly}
- { leftcut must lie in the range 0..15, 16 is allowed (but senseless) }
- MOV AH,[OFFSET BackTile +SI] {AH:=BackTile[index]}
- XOR AL,AL
-
- SHR AH,1 {AX:=tile*64 =tile SHL 6 =(tile SHL 8) SHR 2 }
- RCR AL,1 {therefore: set AH:=tile and afterwards, shift AX }
- SHR AH,1 {2 bits to the right!}
- RCR AL,1
- MOV SI,AX {That's also the offset part of the source ad. in page3}
-
- MOV DI,y {first dest. addr. is DI:=y*LINESIZE+(0 div 4)=y*LINESIZE }
- SHL DI,1
- MOV DI,CS:[OFFSET GADR + DI]
-
- MOV AX,leftcut
- MOV BX,AX {have a copy of leftcut in BX }
- SHR AX,1
- SHR AX,1
- ADD SI,AX {increment SI by cutoff (=leftcut div 4) bytes }
-
- {Now there is no further variable on stack, so BP can be used }
- {for other purposes!}
- PUSH BP {will be needed when leaving the procedure! }
- MOV BP,16+3
- SUB BP,BX {BP:=16+3-leftcut, because the number of bytes per row }
- {of plane i is computed by (16+3-i-leftcut) SHR 2 }
-
-
- MOV ES,PAGEADR {(segment part of) dest. address is active page}
- MOV DS,SCROLLADR {(segment part of) source addr. is page SCROLLPAGE}
-
- MOV DX,3CEh
- AND BL,3
- MOV AH,BL {AH:=leftcut mod 4}
- MOV AL,4
-
- JNE @mode0h {only if leftcut mod 4=0 is it possible to use WriteMode1 }
-
- {--- short-cut possible, using write mode1: DX=3CEh, BP=16+3-leftcut }
- { BP being "3 units to big" doesn't matter, because this code will }
- { only be run if leftcut mod 4=0, thus 16+3-leftcut=...11b, the }
- { "11b" will be cut off while shifting right, anyway! }
- MOV AX,4105h
- OUT DX,AX {choose write mode 1}
- MOV DX,3C4h
- MOV AX,0F02h {work on all 4 planes simultaneously }
- OUT DX,AX
-
- SHR BP,1 {use BP directly }
- SHR BP,1 {BP:=bytes_per_plane3_row }
-
- MOV AX,LINESIZE {adjustment for row target addresses }
- SUB AX,BP { := LINESIZE-bytes_per_plane3_row }
- MOV DX,4 {adjustment for source addresses of the tiles}
- SUB DX,BP { := 4-bytes_per_plane3_row }
-
- MOV CX,BP {CX:=bytes_per_plane2_row }
- REP MOVSB {1.row }
- ADD DI,AX {set DI to next destination row }
- ADD SI,DX {set SI to next tile's source addr. }
- MOV CX,BP
- REP MOVSB {2.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {3.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {4.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {5.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {6.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {7.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {8.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {9.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {10.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {11.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {12.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {13.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {14.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {15.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {16.row }
-
- {--- short cut has been taken: thus, reset write mode 0! }
- MOV AX,4005h
- MOV DX,3CEh
- OUT DX,AX
- {---}
- JMP @LeftTileDone
-
- @mode0h:
- OUT DX,AX {choose plane from which to read}
- PUSH AX {and preserve it for later}
-
- MOV DX,3C4h
- MOV AX,0102h {choose write plane 0 }
- OUT DX,AX
-
- MOV BX,BP
- SHR BX,1
- SHR BX,1 {BX:=bytes_per_plane0_row = (16+3-leftcut) DIV 4 }
-
- MOV AX,LINESIZE {adjustment for row target addresses }
- SUB AX,BX { := LINESIZE-bytes_per_plane0_row }
- MOV DX,4 {adjustment for source addresses of the tiles}
- SUB DX,BX { := 4-bytes_per_plane0_row }
-
- MOV CX,BX {CX:=bytes_per_plane0_row }
- REP MOVSB {1.row }
- ADD DI,AX {set DI to next destination row }
- ADD SI,DX {set SI to next tile's source addr. }
- MOV CX,BX
- REP MOVSB {2.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {3.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {4.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {5.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {6.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {7.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {8.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {9.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {10.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {11.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {12.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {13.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {14.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {15.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {16.row }
- ADD DI,AX
- ADD SI,DX
-
-
- MOV DX,3C4h
- MOV AX,0202h {choose write plane 1 }
- OUT DX,AX
-
- MOV DX,3CEh {next read plane: }
- POP AX
- INC AH
- AND AH,3 {increment by 1 MOD 4}
- JNE @nowrap1h
- INC SI {plane 0 follows after plane 3 again, but}
- {the source address has increased by 1 byte }
- @nowrap1h:
- OUT DX,AX
- PUSH AX
- SUB DI,16*LINESIZE {reset DI and SI registers }
- SUB SI,16*4
-
-
- DEC BP {BP:=16+2-leftcut}
- MOV BX,BP
- SHR BX,1
- SHR BX,1 {BX:=bytes_per_plane1_row }
-
- MOV AX,LINESIZE {adjustment for row target addresses }
- SUB AX,BX { := LINESIZE-bytes_per_plane1_row }
- MOV DX,4 {adjustment for source addresses of the tiles}
- SUB DX,BX { := 4-bytes_per_plane1_row }
-
- MOV CX,BX {CX:=bytes_per_plane1_row }
- REP MOVSB {1.row }
- ADD DI,AX {set DI to next destination row }
- ADD SI,DX {set SI to next tile's source addr. }
- MOV CX,BX
- REP MOVSB {2.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {3.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {4.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {5.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {6.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {7.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {8.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {9.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {10.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {11.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {12.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {13.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {14.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {15.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {16.row }
- ADD DI,AX
- ADD SI,DX
-
-
- MOV DX,3C4h
- MOV AX,0402h {choose write plane 2 }
- OUT DX,AX
-
- MOV DX,3CEh {next read plane: }
- POP AX
- INC AH
- AND AH,3 {increment by 1 MOD 4}
- JNE @nowrap2h
- INC SI {plane 0 follows after plane 3 again, but}
- {the source address has increased by 1 byte }
- @nowrap2h:
- OUT DX,AX
- PUSH AX
- SUB DI,16*LINESIZE {reset DI and SI registers }
- SUB SI,16*4
-
-
- DEC BP {BP:=16+1-leftcut}
- MOV BX,BP
- SHR BX,1
- SHR BX,1 {BX:=bytes_per_plane2_row }
-
- MOV AX,LINESIZE {adjustment for row target addresses }
- SUB AX,BX { := LINESIZE-bytes_per_plane2_row }
- MOV DX,4 {adjustment for source addresses of the tiles}
- SUB DX,BX { := 4-bytes_per_plane2_row }
-
- MOV CX,BX {CX:=bytes_per_plane2_row }
- REP MOVSB {1.row }
- ADD DI,AX {set DI to next destination row }
- ADD SI,DX {set SI to next tile's source addr. }
- MOV CX,BX
- REP MOVSB {2.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {3.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {4.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {5.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {6.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {7.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {8.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {9.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {10.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {11.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {12.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {13.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {14.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {15.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {16.row }
- ADD DI,AX
- ADD SI,DX
-
-
- MOV DX,3C4h
- MOV AX,0802h {choose write plane 3 }
- OUT DX,AX
-
- MOV DX,3CEh {next read plane: }
- POP AX
- INC AH
- AND AH,3 {increment by 1 MOD 4}
- JNE @nowrap3h
- INC SI {plane 0 follows after plane 3 again, but}
- {the source address has increased by 1 byte }
- @nowrap3h:
- OUT DX,AX
- {do not push value again!}
- SUB DI,16*LINESIZE {reset DI and SI registers }
- SUB SI,16*4
-
-
-
- DEC BP {BP:=16-leftcut}
- @lastplane8:
-
- SHR BP,1 {use BP directly }
- SHR BP,1 {BP:=bytes_per_plane3_row }
-
- MOV AX,LINESIZE {adjustment for row target addresses }
- SUB AX,BP { := LINESIZE-bytes_per_plane3_row }
- MOV DX,4 {adjustment for source addresses of the tiles}
- SUB DX,BP { := 4-bytes_per_plane3_row }
-
- MOV CX,BP {CX:=bytes_per_plane2_row }
- REP MOVSB {1.row }
- ADD DI,AX {set DI to next destination row }
- ADD SI,DX {set SI to next tile's source addr. }
- MOV CX,BP
- REP MOVSB {2.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {3.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {4.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {5.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {6.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {7.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {8.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {9.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {10.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {11.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {12.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {13.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {14.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {15.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {16.row }
-
- @LeftTileDone:
- POP BP
- MOV AX,SEG @Data {restore DS }
- MOV DS,AX
-
- MOV CL,offscreenFlag
- XOR SI,SI
- DEC CL
- JZ @go12
- MOV AX,xt
- MOV DX,tiles
- ADD AX,DX
- JS @go12
- CMP AX,XTiles
- JAE @go12
- MOV SI,RandIndex
- ADD SI,DX
- @go12:
-
-
- {PROCEDURE DrawRightTile(x,y,rightcut:INTEGER; index:WORD);}
- { in: (x,y) = upper left corner of the tile to be drawn}
- { rightcut = number of right tile-columns to be cut off }
- { SI = index = tile number}
- {out: tile has been drawn on actual page PAGEADR }
- {rem: tile has been clipped at its right accordingly}
- { rightcut must lie between 0..15, 16 is allowed (but senseless)! }
- { rightcut could also be computed (for x>xmax-16) by }
- { rightcut := x+15-xmax }
- MOV AH,[OFFSET BackTile +SI] {AH:=BackTile[index]}
- XOR AL,AL
-
- SHR AH,1 {AX:=tile*64 =tile SHL 6 =(tile SHL 8) SHR 2 }
- RCR AL,1 {therefore: set AH:=tile and afterwards, shift AX }
- SHR AH,1 {2 bits to the right!}
- RCR AL,1
- MOV SI,AX {That's also the offset part of the source ad. in page3}
-
- MOV DI,y {the first destination addr. is DI:=y*LINESIZE+(x div 4)}
- SHL DI,1
- MOV DI,CS:[OFFSET GADR + DI]
- MOV AX,x
- MOV BX,AX {place a copy of x in BX}
- SHR AX,1
- SHR AX,1
- ADD DI,AX
-
- MOV CX,rightcut
-
- {Now there is no further variable on stack, so BP can be used }
- {for other purposes!}
- PUSH BP {will be needed when leaving the procedure! }
- MOV BP,16+3
- SUB BP,CX {BP:=16+3-rightcut, because the number of bytes per row }
- {of plane i is computed by (16+3-i-rightcut) SHR 2 }
-
-
- MOV ES,PAGEADR {(segment part of) dest. address is active page}
- MOV DS,SCROLLADR {(segment part of) source addr. is page SCROLLPAGE}
-
- MOV DX,3C4h
- MOV AL,2
- AND BX,3
-
- JNE @mode0i {only if x mod 4=0 _and_ rightcut mod 4=0, then we can }
- AND CX,3 {use write mode 1! }
- JNE @mode0i
-
- {--- short-cut possible, using write mode1: DX=3C4h, BP=16+3-rightcut }
- MOV AH,0Fh
- OUT DX,AX {work on all 4 planes simultaneously }
- MOV DX,3CEh
- MOV AX,4105h {choose write mode 1}
- OUT DX,AX
- SUB BP,3 {set BP to proper size }
-
- SHR BP,1 {use BP directly }
- SHR BP,1 {BP:=bytes_per_plane3_row }
-
- MOV AX,LINESIZE {adjustment for row target addresses }
- SUB AX,BP { := LINESIZE-bytes_per_plane3_row }
- MOV DX,4 {adjustment for source addresses of the tiles}
- SUB DX,BP { := 4-bytes_per_plane3_row }
-
- MOV CX,BP {CX:=bytes_per_plane2_row }
- REP MOVSB {1.row }
- ADD DI,AX {set DI to next destination row }
- ADD SI,DX {set SI to next tile's source addr. }
- MOV CX,BP
- REP MOVSB {2.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {3.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {4.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {5.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {6.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {7.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {8.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {9.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {10.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {11.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {12.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {13.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {14.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {15.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {16.row }
-
- {--- short cut has been taken: thus, reset write mode 0! }
- MOV AX,4005h
- MOV DX,3CEh
- OUT DX,AX
- {---}
- JMP @RightTileDone
-
- @mode0i:
- MOV AH,CS:[OFFSET CS_TranslateTab +BX]
- OUT DX,AX {choose plane to write at }
- PUSH AX {and preserve it for later}
-
- MOV DX,3CEh
- MOV AX,0004h {choose read plane 0}
- OUT DX,AX
-
- MOV BX,BP
- SHR BX,1
- SHR BX,1 {BX:=bytes_per_plane0_row = (16+3-rightcut) DIV 4 }
-
- MOV AX,LINESIZE {adjustment for row target addresses }
- SUB AX,BX { := LINESIZE-bytes_per_plane0_row }
- MOV DX,4 {adjustment for source addresses of the tiles}
- SUB DX,BX { := 4-bytes_per_plane0_row }
-
- MOV CX,BX {CX:=bytes_per_plane0_row }
- REP MOVSB {1.row }
- ADD DI,AX {set DI to next destination row }
- ADD SI,DX {set SI to next tile's source addr. }
- MOV CX,BX
- REP MOVSB {2.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {3.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {4.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {5.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {6.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {7.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {8.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {9.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {10.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {11.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {12.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {13.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {14.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {15.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {16.row }
- ADD DI,AX
- ADD SI,DX
-
-
- MOV DX,3CEh
- MOV AX,0104h {choose read plane 1}
- OUT DX,AX
-
- MOV DX,3C4h {next write plane: }
- POP AX
- SHL AH,1
- CMP AH,16
- JNE @nowrap1i
- MOV AH,1 {plane 0 follows after plane 3 again, but}
- INC DI {the destination address has increased by 1 byte}
- @nowrap1i:
- OUT DX,AX
- PUSH AX
- SUB DI,16*LINESIZE {reset DI and SI registers }
- SUB SI,16*4
-
-
- DEC BP {BP:=16+2-rightcut}
- MOV BX,BP
- SHR BX,1
- SHR BX,1 {BX:=bytes_per_plane1_row }
-
- MOV AX,LINESIZE {adjustment for row target addresses }
- SUB AX,BX { := LINESIZE-bytes_per_plane1_row }
- MOV DX,4 {adjustment for source addresses of the tiles}
- SUB DX,BX { := 4-bytes_per_plane1_row }
-
- MOV CX,BX {CX:=bytes_per_plane1_row }
- REP MOVSB {1.row }
- ADD DI,AX {set DI to next destination row }
- ADD SI,DX {set SI to next tile's source addr. }
- MOV CX,BX
- REP MOVSB {2.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {3.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {4.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {5.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {6.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {7.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {8.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {9.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {10.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {11.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {12.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {13.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {14.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {15.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {16.row }
- ADD DI,AX
- ADD SI,DX
-
-
- MOV DX,3CEh
- MOV AX,0204h {choose read plane 2}
- OUT DX,AX
-
- MOV DX,3C4h {next write plane: }
- POP AX
- SHL AH,1
- CMP AH,16
- JNE @nowrap2i
- MOV AH,1 {plane 0 follows after plane 3 again, but}
- INC DI {the destination address has increased by 1 byte}
- @nowrap2i:
- OUT DX,AX
- PUSH AX
- SUB DI,16*LINESIZE {reset DI and SI registers }
- SUB SI,16*4
-
-
- DEC BP {BP:=16+1-rightcut}
- MOV BX,BP
- SHR BX,1
- SHR BX,1 {BX:=bytes_per_plane2_row }
-
- MOV AX,LINESIZE {adjustment for row target addresses }
- SUB AX,BX { := LINESIZE-bytes_per_plane2_row }
- MOV DX,4 {adjustment for source addresses of the tiles}
- SUB DX,BX { := 4-bytes_per_plane2_row }
-
- MOV CX,BX {CX:=bytes_per_plane2_row }
- REP MOVSB {1.row }
- ADD DI,AX {set DI to next destination row }
- ADD SI,DX {set SI to next tile's source addr. }
- MOV CX,BX
- REP MOVSB {2.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {3.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {4.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {5.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {6.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {7.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {8.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {9.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {10.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {11.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {12.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {13.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {14.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {15.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {16.row }
- ADD DI,AX
- ADD SI,DX
-
-
- MOV DX,3CEh
- MOV AX,0304h {choose read plane 3}
- OUT DX,AX
-
- MOV DX,3C4h {next write plane: }
- POP AX
- SHL AH,1
- CMP AH,16
- JNE @nowrap3i
- MOV AH,1 {plane 0 follows after plane 3 again, but}
- INC DI {the destination address has increased by 1 byte}
- @nowrap3i:
- OUT DX,AX
- {do not push value again!}
- SUB DI,16*LINESIZE {reset DI and SI registers }
- SUB SI,16*4
-
-
-
- DEC BP {BP:=16-rightcut}
- @lastplane9:
-
- SHR BP,1 {use BP directly }
- SHR BP,1 {BP:=bytes_per_plane3_row }
-
- MOV AX,LINESIZE {adjustment for row target addresses }
- SUB AX,BP { := LINESIZE-bytes_per_plane3_row }
- MOV DX,4 {adjustment for source addresses of the tiles}
- SUB DX,BP { := 4-bytes_per_plane3_row }
-
- MOV CX,BP {CX:=bytes_per_plane2_row }
- REP MOVSB {1.row }
- ADD DI,AX {set DI to next destination row }
- ADD SI,DX {set SI to next tile's source addr. }
- MOV CX,BP
- REP MOVSB {2.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {3.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {4.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {5.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {6.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {7.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {8.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {9.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {10.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {11.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {12.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {13.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {14.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {15.row }
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {16.row }
-
- @RightTileDone:
- POP BP
- MOV AX,SEG @Data {restore DS }
- MOV DS,AX
-
- MOV AX,RandIndex
- ADD AX,XTiles
- MOV RandIndex,AX
- MOV AX,yt
- INC AX
- MOV yt,AX
- MOV DX,y
- ADD DX,16
- MOV y,DX
- CMP DX,YMAX+1-16
- JBE @repeat5
- @ende:
-
-
- {------- starting here: put sprites on actual graphic page}
- @Sprites_zeichnen:
- MOV SI,NMAX*2
- PUSH BP {pop BP in the end! }
-
- @zeichne:
-
- {DS = normal data segment, ES = graphic page segment, }
- {SI = spritepositionnumber*2 }
- @SZeich:
- MOV BX,[SI + OFFSET SpriteN] {BX=SpriteN[?]=Spriteloadnumber}
- SHL BX,1 {BX = sprite load number*2}
-
- {Now: compute "SpriteN[?]:=SpriteN[NextSprite[?]]" }
- MOV BX,[BX + OFFSET NextSprite] {AX=NextSprite[SpriteN[?]]}
- MOV [SI + OFFSET SpriteN],BX {use it as new SpriteN[?] value }
- SHL BX,1
-
-
- JNZ @aktiv
- JMP @noSprite
-
-
- @aktiv:
- PUSH SI {save spritepositionnumber*2 }
-
- MOV DX,[SI + OFFSET SpriteX] {if SpriteX>xmax then skip_sprite }
- SUB DX,StartVirtualX {virtual -> absolute coordinates }
- CMP DX,XMAX
- JLE @L0
- @ToSprite_fertig: {jump-rail to @Sprite_fertig }
- JMP @Sprite_fertig
- @L0:
- MOV CS:WORD PTR @akt_SpriteX+1,DX
- MOV DI,[SI + OFFSET SpriteY] {DI = SpriteY_virtual }
- SUB DI,StartVirtualY {DI = SpriteY (absolute!)}
- MOV DS,[BX + OFFSET SPRITEAD] {!!!DS = ^sprite data !!!}
- MOV AX,[Breite] {AX = width in groups of 4 }
- MOV CS:WORD PTR @max_Breite+1,AX
- MOV SI,AX {SI = dto.}
- SHL AX,1
- SHL AX,1 {AX = max_width_in_points }
- ADD AX,DX {AX = max_width_in_points+SpriteX }
- JS @ToSprite_fertig
- MOV BX,DI {if SpriteY>=0 then starty:=+SpriteY}
- NEG DI { else starty:=-SpriteY}
- MOV BP,DI
- JG @Top_cut
- XOR DI,DI
- @Top_cut: {DI = starty, BP = -SpriteY}
- MOV AX,[Hoehe] {AX = height (in rows) }
- CMP DI,AX {if starty>=height then skip_sprite}
- JGE @ToSprite_fertig
- ADD BP,YMAX {BP = -SpriteY+ymax}
- JL @ToSprite_fertig {(a bit lax:) }
- CMP AX,BP {if height+SpriteY>ymax }
- JG @To_then { then [ endy:=199-SpriteY }
- DEC AX { if endy<0 then skip_sprite ] }
- MOV BP,AX { else endy:=height-1 }
-
- {BP = endy, SI=[@max_Breite+1] = max_width_in_groups of 4, }
- {DI = starty, BX = SpriteY, DX=[@akt_SpriteX+1] = SpriteX, }
- {DS = ^sprite data, ES = ^graphic page}
- @To_then:
- MOV AX,BP
- SUB BP,DI
-
- SHL BP,1
- MOV [End_min_Start],BP {= (endy-starty)*2 =Yaktuell*2}
- ADD BX,AX
- SHL BX,1
- MOV BX,CS:[OFFSET gadr + BX] {BX=zeilenadr:=(endy+SpriteY)*LINESIZE}
- MOV [zeilenadr],BX {store it in [zeilenadr], too }
- MOV BP,DX
- MUL SI {AX=endy*max_width_in_groups_of_4=yoffset}
- MOV [yoffset_],AX {store it in [yoffset_], too}
- SHL DI,1 {DI = starty*2}
- MOV CS:WORD PTR @Starty_2+1,DI {store it in [@Starty_2+1], too }
-
- {Now: look at sprite's mode byte and determine if an other than the }
- {momentary active sprite display method is needed; if so, then copy }
- {in the right one! }
- {used registers: AX and SI }
- MOV AL,[Modus] {get mode byte of the sprite}
- XOR AH,AH
- SHL AX,1
- MOV SI,AX
- MOV SI,CS:[OFFSET Adressen +SI] {get pointer to according routine }
- MOV AX,CS:[SI]
- CMP AX,CS:[WORD PTR @Patch1] {is this routine already active? }
- JE @no_newcode {yes, nothing to do}
- PUSH DS {no, copy routine to all places }
- PUSH CS {where it will be needed}
- POP DS
- MOV [WORD PTR @Patch1],AX
- MOV [WORD PTR @Patch2],AX
- MOV [WORD PTR @Patch3],AX
- MOV [WORD PTR @Patch4],AX
- INC SI
- INC SI
- LODSW
- MOV [WORD PTR @Patch1+2],AX
- MOV [WORD PTR @Patch2+2],AX
- MOV [WORD PTR @Patch3+2],AX
- MOV [WORD PTR @Patch4+2],AX
- LODSW
- MOV [WORD PTR @Patch1+4],AX
- MOV [WORD PTR @Patch2+4],AX
- MOV [WORD PTR @Patch3+4],AX
- MOV [WORD PTR @Patch4+4],AX
- LODSW
- MOV [WORD PTR @Patch1+6],AX
- MOV [WORD PTR @Patch2+6],AX
- MOV [WORD PTR @Patch3+6],AX
- MOV [WORD PTR @Patch4+6],AX
- LODSW
- MOV [WORD PTR @Patch1+8],AX
- MOV [WORD PTR @Patch2+8],AX
- MOV [WORD PTR @Patch3+8],AX
- MOV [WORD PTR @Patch4+8],AX
- LODSW
- MOV [WORD PTR @Patch1+10],AX
- MOV [WORD PTR @Patch2+10],AX
- MOV [WORD PTR @Patch3+10],AX
- MOV [WORD PTR @Patch4+10],AX
- LODSW
- MOV [WORD PTR @Patch1+12],AX
- MOV [WORD PTR @Patch2+12],AX
- MOV [WORD PTR @Patch3+12],AX
- MOV [WORD PTR @Patch4+12],AX
- LODSW
- MOV [WORD PTR @Patch1+14],AX
- MOV [WORD PTR @Patch2+14],AX
- MOV [WORD PTR @Patch3+14],AX
- MOV [WORD PTR @Patch4+14],AX
-
- POP DS {restore DS }
- @no_newcode:
-
-
- {(AX=)[yoffset_] = yoffset }
- { BX=[zeilenadr] = (endy+SpriteY)*LINESIZE}
- { DI=[@Starty_2+1] = starty*2}
- {(SI=[@max_Breite+1] = max_width_in_groups_of_4) }
- { BP = SpriteX}
- { DS = ^sprite data}
- { ES = ^graphic page}
- { [end_min_start] = (endy-starty)*2 =Yaktuell*2}
- { [@max_Breite+1] = max_width_in_groups_of_4 }
- { [@akt_SpriteX+1] = SpriteX}
- @eine_Zeile:
- MOV SI,[end_min_start] {SI = Yactual*2 }
- ADD SI,DI {startx:=sprite[WORD PTR sprite[L]+ }
- MOV DI,SI { (Yactual+starty)*2] }
- ADD SI,[Left]
- MOV SI,[SI] {SI = startx, DI = (Yaktuell+starty)*2}
- MOV AX,BP
- ADD AX,SI {AX=ScreenStartX:=SpriteX+startx }
- CMP AX,XMAX {if ScreenStartX>xmax then skip_zeile }
- JG @ToZeile_fertig
- MOV CX,SI {CX=startx}
- OR AX,AX {lecutoff_in_points:=startx }
- JGE @L1 {if ScreenStartX<0 then }
- SUB SI,AX { [dec(startx,ScreenStartX) }
- XOR AX,AX { ScreenStartX:=0 }
- MOV CX,BP { lecutoff_in_points:=-SpriteX] }
- NEG CX
- @L1: {CX=[licutoff_]= licutoff_in_points, }
- MOV [licutoff_],CX {SI = startx, AX = ScreenStartX }
- ADD DI,[Right]
- MOV DI,[DI] {DI=endx:=sprite[WORD PTR sprite[R]+ }
- { (Yactual+starty)*2] }
- MOV DX,BP
- NEG DX {DX = -SpriteX }
- MOV BP,DI
- SUB BP,SI {BP = endx-startx }
- SUB DX,DI
- ADD DX,XMAX {DX=overhang :=xmax-(SpriteX+endx) }
- JNS @kein_Ueberhang_rechts
- ADD BP,DX
- @kein_Ueberhang_rechts: {BP = visible width of this row -1 }
- OR BP,BP
- JNS @L6
- @ToZeile_fertig:
- JMP @Zeile_fertig {if width<=0 then skip_zeile }
- @L6:
- ADD BP,4
-
- { AX = ScreenStartX }
- { BX=[zeilenadr] = (endy+SpriteY)*LINESIZE }
- { CX=[licutoff_] = lecutoff_in_points }
- {(DX = (negative) overhang (if value<0) ) }
- {(SI = startx) }
- {(DI = endx) }
- { BP = width of this row in pixels +3 }
- { DS = ^sprite data}
- { ES = ^graphic page}
- { [@max_Breite+1] = max_width_in_groups_of_4) }
- { [end_min_start] = (endy-starty)*2 =Yaktuell*2}
- { [@Starty_2+1] = starty*2}
- { [@max_Breite+1] = max_width_in_groups_of_4, }
- { [@akt_SpriteX+1] = SpriteX}
- MOV [bildx],AX {save ScreenStartX }
- MOV DX,CX {DX = lecutoff_in_points }
- MOV CX,BP
- SHR CX,1
- SHR CX,1 {CX = width DIV 4 }
- JCXZ @Plane1
-
- {SI=source pointer:=sprite[WORD PTR (lecutoff_in_points+0 AND 3)*2 }
- { +(lecutoff_in_points+0) DIV 4 +yoffset }
- MOV SI,DX
- AND SI,3
- SHL SI,1 {SI = ((lecutoff_in_points+0) AND 3)*2 }
- MOV SI,[SI]
- MOV DI,DX
- SHR DI,1
- SHR DI,1
- ADD SI,DI
- ADD SI,[yoffset_] {SI = sprite[WORD PTR (licutoff_...)] }
- { +(lecutoff_in_points+i) DIV 4 }
- { +yoffset }
-
- {DI=dest.ptr:=(ScreenStartX+0) DIV 4 +zeilenadr }
- MOV DI,AX {DI = ScreenStartX }
- SHR DI,1
- SHR DI,1
- ADD DI,BX
- MOV BL,AL
- AND BX,3 {BX = (ScreenStartX+i) AND 3 }
- MOV AH,Translate[BX] {AH = 1,2,4,8 for BX=0,1,2,3 }
- MOV AL,2
- MOV DX,3C4h
- OUT DX,AX {choose plane }
-
- XCHG BX,DI
- {copy CX bytes from DS:SI to ES:BX }
- {this is the address where the data transfer routine will be patched!}
- @Patch1:
- db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-
- @Plane1:
- MOV DX,[bildx]
- INC DX {DX = ScreenStartX+1 }
- MOV BX,DX
- SHR BX,1
- SHR BX,1 {BX=dest. ptr :=(ScreenStartX+1) }
- ADD BX,[zeilenadr] { DIV 4 +zeilenadr }
- MOV CX,BP
- DEC CX {CX = width of this line +3 -1 }
- SHR CX,1
- SHR CX,1 {CX = bytes_to_move for i=1 }
- JCXZ @Plane2
- MOV DI,[licutoff_]
- INC DI {DI = (lecutoff_in_points+1) }
- MOV SI,DI
- AND SI,3
- SHL SI,1 {SI = ((lecutoff_in_points+1) AND 3)*2 }
- MOV SI,[SI] {SI = sprite[WORD PTR licutoff_...] }
- SHR DI,1 { +(lecutoff_in_points+1) DIV 4 }
- SHR DI,1 { +yoffset }
- ADD SI,DI
- ADD SI,[yoffset_] {SI = source pointer, }
- {DI = (lecutoff_in_points+1) DIV 4 }
-
- MOV DI,DX {DI = ScreenStartX+1 }
- AND DI,3 {DI = (ScreenStartX+1) AND 3 }
- MOV AH,Translate[DI] {load mask for port-access }
- MOV AL,2
- MOV DX,3C4h {select plane }
- OUT DX,AX
-
- {this is the address where the data transfer routine will be patched!}
- @Patch2:
- db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-
- @Plane2:
- MOV DX,[bildx]
- ADD DX,2
- MOV BX,DX
- SHR BX,1
- SHR BX,1
- ADD BX,[zeilenadr]
- MOV CX,BP
- SUB CX,2
- SHR CX,1
- SHR CX,1
- JCXZ @Plane3
- MOV DI,[licutoff_]
- ADD DI,2
- MOV SI,DI
- AND SI,3
- SHL SI,1
- MOV SI,[SI]
- SHR DI,1
- SHR DI,1
- ADD SI,DI
- ADD SI,[yoffset_]
-
- MOV DI,DX {DI = ScreenStartX+2 }
- AND DI,3 {DI = (ScreenStartX+1) AND 3 }
- MOV AH,Translate[DI]
- MOV AL,2
- MOV DX,3C4h
- OUT DX,AX
-
- {this is the address where the data transfer routine will be patched!}
- @Patch3:
- db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-
- @Plane3:
- MOV DX,[bildx]
- ADD DX,3
- MOV BX,DX
- SHR BX,1
- SHR BX,1
- ADD BX,[zeilenadr]
- MOV CX,BP
- SUB CX,3
- SHR CX,1
- SHR CX,1
- JCXZ @Zeile_fertig
- MOV DI,[licutoff_]
- ADD DI,3
- MOV SI,DI
- AND SI,3
- SHL SI,1
- MOV SI,[SI]
- SHR DI,1
- SHR DI,1
- ADD SI,DI
- ADD SI,[yoffset_]
-
- MOV DI,DX {DI = ScreenStartX+3 }
- AND DI,3 {DI = (ScreenStartX+1) AND 3 }
- MOV AH,Translate[DI]
- MOV AL,2
- MOV DX,3C4h
- OUT DX,AX
-
- {this is the address where the data transfer routine will be patched!}
- @Patch4:
- db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-
- @Zeile_fertig:
- MOV AX,[yoffset_]
- @max_Breite:
- SUB AX,1234
- MOV [yoffset_],AX
- MOV BX,[zeilenadr]
- SUB BX,LINESIZE
- MOV [zeilenadr],BX
- SUB WORD PTR [end_min_start],2
- JS @Sprite_fertig
-
- @Starty_2:
- MOV DI,1234
- @akt_SpriteX:
- MOV BP,1234
- JMP @eine_Zeile
-
- @Sprite_fertig:
- POP SI
- MOV AX,SEG @Data
- MOV DS,AX
-
- @noSprite:
- DEC SI
- DEC SI
- JS @fertig
- JMP @zeichne
- @fertig:
-
- POP BP
-
- {The graphic page is now ready to be displayed: }
- cli
- mov dx,StatusReg
-
- {Wait for "display enable"=0 (that is: active), so that page flipping }
- {for HB/LB takes place while displaying the same page:}
-
- @WaitNotHSyncLoop:
- in al,dx
- and al,1
- jnz @WaitNotHSyncLoop
- @WaitHSyncLoop:
- in al,dx
- and al,1
- jz @WaitHSyncLoop
-
- MOV DX,CRTAddress {CRT-Controller}
- MOV AL,$0D {LB-startaddress-register}
- OUT DX,AL
- INC DX
- { realize "AX:=Offset_Adr[Page]": }
- MOV SI,PAGE {page value *2 (word-sized entries!)}
- MOV BX,SI {save page value to BX! }
- SHL SI,1 {add start address of array to that }
- ADD SI,OFFSET Offset_Adr-StartIndex*2 {evtl. correct displacement }
- LODSW {and fetch value}
- OUT DX,AL {set LB of new starting address }
- DEC DX
- MOV AL,$0C
- OUT DX,AL
- INC DX
- MOV AL,AH {set HB of new starting address }
- OUT DX,AL
- STI
-
- NEG BX {new PAGE-value := 1-old PAGE-value, that is: }
- ADD BX,1 {IF PAGE=0 THEN PAGE:=1 ELSE (PAGE=1) PAGE:=0 }
- MOV PAGE,BX
-
- SHL BX,1 {new PAGEADR-value := Segment_Adr[PAGE] }
- ADD BX,OFFSET Segment_Adr-StartIndex*2
- MOV AX,[BX]
- MOV PAGEADR,AX
-
- {Check whether the preset (min.) cycle time has passed: }
- @L10:
- MOV AL,TimeFlag {bit 7 = 0/1 for delay completed/not yet completed }
- AND AL,$80
- JE @L10
-
- {start time control mechanism for next cycle: }
- MOV AL,IsAT {is this an AT or better? ($0/$80=yes/no)}
- OR AL,AL {timing mechanism only works on AT/386 }
- JNE @L11 {otherwise: no timing mechanism! }
- MOV TimeFlag,AL {use AL=0 as starting value, too }
- MOV DX,WORD PTR CycleTime {store min. time for 1 cycle (micro- }
- MOV CX,WORD PTR CycleTime+2 {seconds: CX=HIGH-Word, DX=LOW-Word }
- MOV BX,OFFSET TimeFlag {ES:BX=pointer to TimeFlag, bit 7=0/1}
- MOV AX,DS {for: delay still lasts/has ended }
- MOV ES,AX
- MOV AX,8300h {start time control mechanism}
- INT 15h
- @L11:
- END
- END;
-
-
- FUNCTION LoadSprite(name:String; number:WORD):WORD;
- { in: name = name of the sprite file to load (type: "*.COD" / "*.LIB") }
- { number = number for the first sprite of this file }
- {out: number of the sprites read in from the file (0 = error occured) }
- {rem: The routine automatically detects whether the specified file con- }
- { tains a single sprite or a complete sprite library and loads all }
- { sprite data into the heap, in a way such that the address always }
- { lies on a segment (=paragraph) boundary. These starting addresses }
- { are then stored in table SPRITEAD[number]; if more than one sprite }
- { has been loaded, they will be stored with consecutive numbers, that }
- { is, number+i }
- LABEL quit_loop;
- VAR p1,p2:Pointer;
- len:LONGINT;
- f:File;
- count,Kopf:WORD;
- Header:SpriteHeader;
- BEGIN
- count:=0; {number of sprites already read in }
- Kopf:=SizeOf(SpriteHeader);
- assign(f,name);
- {$I-} reset(f,1); {$I+}
- if (ioresult<>0)
- THEN BEGIN {File doesn't exist or at least not with that path }
- Error:=Err_FileIO;
- loadSprite:=0; exit
- END;
- len:=filesize(f); {determine file length}
- if (maxavail<len+16)
- THEN BEGIN
- Error:=Err_NotEnoughMemory;
- goto quit_loop;
- END;
- if (number=0) or (number>LoadMAX)
- THEN BEGIN
- Error:=Err_InvalidSpritenumber;
- goto quit_loop;
- END;
- WHILE NOT EOF(f) DO
- BEGIN
- {first, read in the sprite header: }
- {$I-} {load sprite header vià BLOCKREAD into the heap }
- blockread(f,Header,Kopf);
- {$I+}
-
- IF (ioresult<>0)
- THEN BEGIN
- Error:=Err_FileIO;
- goto quit_loop;
- END;
- IF (Header.Kennung[1]<>'K') or (Header.Kennung[2]<>'R')
- THEN BEGIN
- Error:=Err_NoSprite;
- goto quit_loop;
- END;
- IF (Header.SpriteLength>MaxAvail+15) {enough space left? }
- THEN BEGIN
- Error:=Err_NotEnoughMemory;
- goto quit_loop;
- END;
-
- {Now read in the real sprite data: }
- getmem(p1,Header.SpriteLength+15); {get enough space }
- IF (LONGINT(p1) mod 16)=0
- THEN p2:=p1 {make p2 fall on segment boundary}
- ELSE LONGINT(p2):=LONGINT(p1) + (16-LONGINT(p1) mod 16);
-
- MOVE(Header,p2^,Kopf); {store sprite header to heap }
- LONGINT(p1):=LONGINT(p2)+Kopf; {points exactly behind the header}
-
- {$I-} {load the "rest" of the sprite }
- blockread(f,p1^,Header.SpriteLength-Kopf);
- {$I+}
- IF (ioresult<>0)
- THEN BEGIN
- Error:=Err_FileIO;
- goto quit_loop;
- END;
-
- {assign it to the sprite number:}
- spritead[number+count]:=(longint(p2) shr 16)
- +(longint(p2) and 65535) shr 4;
- INC(count);
- END;
-
- quit_loop: ;
- close(f);
- loadSprite:=count
- END;
-
- FUNCTION LoadTile(name:STRING; number:BYTE):WORD;
- { in: name = name of the sprite file to load (type: "*.COD" / "*.LIB") }
- { number = 0..255 = tile number for the file's first sprite }
- {out: number of the tiles read in from the file (0 = error occured) }
- {rem: The routine automatically detects whether the specified file con- }
- { tains a single sprite or a complete sprite library and loads all }
- { sprites, splits them into tiles and stores them into the 4th graphic }
- { page, starting with the given number "number" }
- { Because a tile consists of 16x16 points, the sprites must be a mul- }
- { tiple of 16 points in each direction (x _and_ y) }
- { If the file contains more than one tile, they will be loaded by row,}
- { each row from left to right }
- LABEL quit_loop;
- TYPE split=RECORD loword,hiword:WORD END;
- VAR p1:Pointer;
- len,ad,p:LONGINT;
- f:File;
- count,Kopf,ZielOfs,step,yoffset:WORD;
- pSeg,pOfs:ARRAY[0..3] OF WORD;
- Breite_in_Tiles,Hoehe_in_Tiles,x,y,i,zeilen:BYTE;
- Header:SpriteHeader;
- BEGIN
- count:=0; {number of sprites already read in }
- Kopf:=SizeOf(SpriteHeader);
- assign(f,name);
- {$I-} reset(f,1); {$I+}
- if (ioresult<>0)
- THEN BEGIN {File doesn't exist or at least not with that path }
- Error:=Err_FileIO;
- LoadTile:=0; exit
- END;
- len:=filesize(f); {determine file length}
- if (maxavail<len+16)
- THEN BEGIN
- Error:=Err_NotEnoughMemory;
- goto quit_loop;
- END;
- WHILE NOT EOF(f) DO
- BEGIN
- {first, read in the sprite header: }
- {$I-} {load sprite header vià BLOCKREAD into the heap }
- blockread(f,Header,Kopf);
- {$I+}
-
- IF (ioresult<>0)
- THEN BEGIN
- Error:=Err_FileIO;
- goto quit_loop;
- END;
- IF (Header.Kennung[1]<>'K') or (Header.Kennung[2]<>'R')
- THEN BEGIN
- Error:=Err_NoTile; {or Err_NoSprite! }
- goto quit_loop
- END;
- IF (Header.Breite_in_4er_Gruppen MOD 4<>0) OR
- (Header.Hoehe_in_Zeilen MOD 16<>0) {size a multiple of 16? }
- THEN BEGIN
- Error:=Err_NoTile;
- goto quit_loop
- END
- ELSE BEGIN {yes, get number of tiles in that sprite file }
- Breite_in_Tiles:=Header.Breite_in_4er_Gruppen SHR 2;
- Hoehe_in_Tiles :=Header.Hoehe_in_Zeilen SHR 4;
- step:=Breite_in_Tiles*4; {"step" needed for correct addressing}
- END;
- IF (Header.SpriteLength>MaxAvail) {enough space left? }
- THEN BEGIN
- Error:=Err_NotEnoughMemory;
- goto quit_loop;
- END;
-
- {Now read in the real sprite data: }
- getmem(p1,Header.SpriteLength); {get enough space }
-
- {$I-} {load the "rest" of the sprite }
- blockread(f,p1^,Header.SpriteLength-Kopf);
- {$I+}
- IF (ioresult<>0)
- THEN BEGIN
- Error:=Err_FileIO;
- goto quit_loop;
- END;
-
- ad:=(LONGINT(split(p1).HiWord) SHL 4) + split(p1).LoWord - Kopf;
- FOR i:=0 TO 3 DO
- BEGIN
- p:=ad+Header.Zeiger_auf_Plane[i]; pSeg[i]:=p SHR 4; pOfs[i]:=p AND $F;
- END;
-
- FOR y:=0 TO Pred(Hoehe_in_Tiles) DO
- BEGIN
- yoffset:=y*Breite_in_Tiles*16*(16 DIV 4);
- FOR x:=0 TO Pred(Breite_in_Tiles) DO
- BEGIN
- IF count+number>255
- THEN BEGIN
- Error:=Err_InvalidTileNumber;
- goto quit_loop
- END;
- ZielOfs:=(number+count) SHL 6;
- FOR i:=0 TO 3 DO
- BEGIN
- PORTW[$3C4]:=(TranslateTab[i] SHL 8) + 2;
- FOR zeilen:=0 TO 15 DO
- BEGIN
- move(mem[pSeg[i]:pOfs[i] + yoffset + zeilen*step + x*(16 DIV 4)],
- mem[SCROLLADR:ZielOfs + zeilen*(16 DIV 4)],
- 16 DIV 4);
- END;
- END;
-
- INC(count);
- END;
- END;
- Dispose(p1);
- END;
-
- quit_loop: ;
- close(f);
- LoadTile:=count
- END;
-
- PROCEDURE SetBackgroundScrollRange(x1,y1,x2,y2:INTEGER);
- { in: (x1,y1) = upper left corner of the area (in virtual coord.)}
- { (x2,y2) = dto., lower right corner}
- {out: (BackX1,BackY1), (BackX2,BackY2) = coord., rounded to 16'grid }
- { XTiles, YTiles = width and height of the chosen range in tiles }
- {rem: The upper left corner will be torn to the upper left, the lower }
- { right corner to the lower right!}
- { Obviously, calling the routine only makes sense when using SCROLLING }
- { as background mode! }
- BEGIN
- BackX1:=x1 AND $FFF0; BackX2:=x2 OR $F;
- BackY1:=y1 AND $FFF0; BackY2:=y2 OR $F;
- xtiles:=succ(BackX2-BackX1) shr 4;
- ytiles:=succ(BackY2-BackY1) shr 4;
- IF (xtiles OR ytiles)<=0
- THEN Error:=Err_InvalidCoordinates
- ELSE IF xtiles*ytiles>MaxTiles
- THEN Error:=Err_BackgroundToBig;
- END;
-
- PROCEDURE SetBackgroundMode(mode:BYTE);
- { in: mode = wanted background mode, STATIC or SCROLLING }
- {out: Backgroundmode = set mode, STATIC/SCROLLING }
- BEGIN
- IF (mode<>STATIC) AND (mode<>SCROLLING)
- THEN Error:=Err_InvalidMode
- ELSE Backgroundmode:=mode
- END;
-
- PROCEDURE PutTile(x,y:INTEGER; TileNr:BYTE);
- { in: x,y = virtual coordinates where the tile shall be placed }
- { TileNr= number of the tile to be placed }
- {out: - }
- {rem: The point (x,y) first gets rounded to a grid with mesh 16 }
- { Calling this routine only makes sense when using SCROLLING}
- { as background mode! }
- VAR index:WORD;
- BEGIN
- ASM
- MOV AX,x {compute relative X-distance from left edge of }
- SUB AX,BackX1 {the defined area and store it to "x", formula: }
- SAR AX,1 { x:=((x AND $FFF0)-BackX1) DIV 16 (not: SHR 4)! }
- SAR AX,1 {"AND $FFF0" isn't needed, because in BackX1, the }
- SAR AX,1 {last hex-digit is $0! }
- SAR AX,1
- MOV x,AX
-
- MOV AX,y {dto. for distance between the y-coordinate and }
- SUB AX,BackY1 {top boundary: y:=((y AND $FFF0)-BackY1) DIV 16 }
- SAR AX,1
- SAR AX,1
- SAR AX,1
- SAR AX,1
- MOV y,AX
- END;
-
- IF (x<0) OR (x>=XTiles) OR (y<0) OR (y>=YTiles)
- THEN Error:=Err_InvalidCoordinates
- ELSE BEGIN {a tile row has width XTiles, each tile consists of 16x16 points}
- index:=y*XTiles+x; {to be exact: (x MOD XTiles)}
- BackTile[Succ(index)]:=TileNr; {"succ", to hold free BackTile[0] }
- END;
- END;
-
- PROCEDURE SetOffscreenTile(TileNr:BYTE);
- { in: TileNr= number of the tile to be placed }
- {out: - }
- {rem: all screen parts, which lie outside the window specified by }
- { SetBackgroundScrollRange will become the tile TileNr as }
- { pattern }
- { Calling this routine only makes sense when using SCROLLING }
- { as background mode! }
- BEGIN
- BackTile[0]:=TileNr
- END;
-
- PROCEDURE SetModeByte(Sp:WORD; M:BYTE);
- { in: Sp = spriteLOADnumber, which mode byte shall be changed }
- {out: M = method, which shall be used to display Sp from now on: }
- { Display_NORMAL, Display_FAST, Display_SHADOW or }
- { Display_SHADOWEXACT }
- {rem: If the sprite doesn't exist yet (or the mode isn't allowed), }
- { nothing will happen at all! }
- VAR ad:WORD;
- BEGIN
- ad:=SPRITEAD[Sp];
- IF ad=0 THEN Error:=Err_InvalidSpriteNumber {sprite must already be loaded }
- ELSE IF (M<Display_NORMAL) OR (M>Display_SHADOWEXACT)
- THEN Error:=Err_InvalidMode {only these 4 modes are allowed }
- ELSE MEM[ad:Modus]:=M
- END;
-
- FUNCTION GetModeByte(Sp:WORD):BYTE;
- { in: Sp = spriteLOADnumber, which mode byte shall be determined }
- {out: actually set display method for sprite Sp: Display_NORMAL, }
- { Display_FAST, Display_SHADOW, Display_SHADOWEXACT or }
- { Display_UNKNOW, if the sprite hasn't been loaded, yet! }
- VAR ad:WORD;
- BEGIN
- ad:=SPRITEAD[Sp];
- IF (ad=0)
- THEN GetModeByte:=Display_UNKNOWN {sprite not yet loaded }
- ELSE GetModeByte:=MEM[SPRITEAD[Sp]:Modus]
- END;
-
- PROCEDURE FillPage(pa,color:Byte);
- { in: pa = the page which shall be filled (0..3) }
- { color = color with which to fill the page}
- {out: graphic page "pa" has been filled with color "Color" }
- {rem: Only "pa" values of 0,1 and BACKGNDPAGE make sense, but }
- { SCROLLPAGE is allowed, too }
- BEGIN
- IF (pa<>0) AND (pa<>1) AND (pa<>BACKGNDPAGE) AND (pa<>SCROLLPAGE)
- THEN Error:=Err_InvalidPageNumber
- ELSE BEGIN
- portw[$3C4]:=$0F02; {use MapMask register to select all 4 planes }
- fillchar(MEM[Segment_Adr[pa]:0],PAGESIZE,Color)
- END;
- END;
-
- PROCEDURE FillBackground(color:BYTE);
- { in: color = color for filling the background page BACKGNDPAGE }
- {out: The graphic page BACKGNDPAGE has been filled with color "Color" }
- {rem: Using the routine only makes sense when using background mode STATIC }
- BEGIN
- FillPage(BACKGNDPAGE,color)
- END;
-
- PROCEDURE GetBackgroundFromPage(pa:Byte);
- {in : pa = 0 or 1 }
- {out: - }
- {rem: The background page BACKGNDPAGE has been filled with the con- }
- { tents of the supplied graphic page.}
- { Using the routine only makes sense when using background mode STATIC }
- VAR p:POINTER;
- BEGIN
- IF (pa<>0) AND (pa<>1)
- THEN Error:=Err_InvalidPageNumber
- ELSE BEGIN
- portw[$3c4]:=$0f02; {use MapMask register to select all 4 planes }
- port[$3ce]:=5; {write mode 1 }
- port[$3cf]:=port[$3cf] OR 1; {or directly :=$41}
- p:=Ptr(Segment_Adr[pa],$0000);
- MOVE(p^,MEM[BACKGNDADR:0],PAGESIZE);
- portw[$3cf]:=port[$3cf] and $FC; {write mode 0 (or directly :=$40) }
- END;
- END;
-
- PROCEDURE WritePage(name:STRING; pa:BYTE);
- { in: name = file name for the picture to store }
- { pa = page to store (0..2) }
- { PAGESIZE = size of one bitplane }
- { PICHeader= tag for picture file }
- {out: - }
- {rem: The picture at page "pa" has been stored (as bitmap) to file "name" }
- { This file has size 4*PAGESIZE+3 = 64003 bytes: 320x200 points , }
- { 1 byte plus length(PICHeader) as tag }
- VAR f:FILE;
- i,oldMode:BYTE;
- fehler:BOOLEAN;
- BEGIN
- IF (pa<>0) AND (pa<>1) AND (pa<>BACKGNDPAGE)
- THEN BEGIN
- Error:=Err_InvalidPageNumber; exit
- END;
- {$I-}
- Assign(f,name); fehler:=IOResult<>0;
- Rewrite(f,1); fehler:=fehler OR (IOResult<>0);
- BlockWrite(f,PICHeader[1],Length(PICHeader));
- fehler:=fehler OR (IOResult<>0);
- {$I+}
- IF fehler
- THEN BEGIN
- {$I-} Close(f); {$I+}
- Error:=Err_FileIO; exit
- END;
- port[$3ce]:=5; {save old read-/write mode }
- oldMode:=port[$3cf];
- port[$3cf]:=$40; {set read mode 0 }
- FOR i:=0 TO 3 DO
- BEGIN
- portw[$3CE]:=4+(i shl 8); {select read plane }
- {$I-}
- BlockWrite(f,mem[Segment_Adr[pa]:0],PAGESIZE);
- {$I+}
- fehler:=fehler OR (IOResult<>0);
- END;
- {$I-}
- Close(f);
- {$I+}
- fehler:=fehler OR (IOResult<>0);
- port[$3ce]:=5; {restore old read-/write mode }
- port[$3cf]:=oldMode;
- IF fehler THEN Error:=Err_FileIO
- END;
-
- PROCEDURE LoadPage(name:STRING; pa:BYTE);
- { in: name = file name for the picture to load}
- { pa = destination page to be loaded with the picture (0..2) }
- { PAGESIZE = size of one bitplane }
- { PICHeader= tag for picture files }
- {out: - }
- {rem: The bitmap-picture in file "name" has been loaded into page "pa" }
- VAR f:FILE;
- i,oldMode:BYTE;
- fehler:BOOLEAN;
- s:STRING[3];
- splane:WORD;
- p1,p2:POINTER;
- TYPE tempArray=ARRAY[1..PAGESIZE] OF BYTE;
- VAR temp:^tempArray;
- BEGIN
- IF (pa<>0) AND (pa<>1) AND (pa<>BACKGNDPAGE)
- THEN BEGIN
- Error:=Err_InvalidPageNumber; exit
- END;
- {$I-}
- Assign(f,name); fehler:=IOResult<>0;
- Reset(f,1); fehler:=fehler OR (IOResult<>0);
- s[0]:=PICHeader[0];
- BlockRead(f,s[1],Length(PICHeader)); fehler:=fehler OR (IOResult<>0);
- {$I+}
- IF fehler
- THEN BEGIN
- {$I-} Close(f); {$I+}
- Error:=Err_FileIO; exit
- END
- ELSE IF (FileSize(f)<>4*PAGESIZE+Length(PICHeader)) OR (s<>PICHeader)
- THEN BEGIN
- {$I-} Close(f); {$I+}
- Error:=Err_NoPicture; exit
- END;
- ASM cli END;
- port[$3ce]:=5; {save old read-/write mode }
- oldMode:=port[$3cf];
- New(temp);
- ASM sti END;
- FOR i:=0 TO 3 DO
- BEGIN
- {$I-}
- BlockRead(f,temp^[1],PAGESIZE);
- {$I+}
- fehler:=fehler OR (IOResult<>0);
- splane:=2+(TranslateTab[i] shl 8); {which write plane }
- p1:=@temp^[1];
- p2:=ptr(Segment_Adr[pa],0);
- ASM
- cli
- mov dx,$3CE {select write mode 0 }
- mov ax,$4005
- out dx,ax
-
- mov ax,splane {select write plane }
- mov dx,$3C4
- out dx,ax
-
- les di,p2
- lds si,p1
- mov cx,PAGESIZE SHR 1
- rep movsw
-
- mov ax,SEG @DATA
- mov ds,ax
- sti
- END;
-
- END;
- Dispose(temp);
- {$I-}
- Close(f);
- {$I+}
- fehler:=fehler OR (IOResult<>0);
- portw[$3ce]:=oldMode SHL 8 + 5; {restore old read-/write mode }
- IF fehler THEN Error:=Err_FileIO
- END;
-
- PROCEDURE WriteBackgroundPage(name:STRING);
- { in: name = file name for the background picture to store }
- { BACKGNDPAGE= page to be saved (=2) }
- { PAGESIZE = size of one bitplane }
- { PICHeader = tag for picture file }
- {out: - }
- {rem: The picture of the background page has been stored as file "name" }
- { This file has size 4*PAGESIZE+3 = 64003 bytes: 320x200 points }
- { at 1 byte each, plus length(PICHeader) as tag }
- { Using the routine only makes sense when using background mode STATIC }
- BEGIN
- WritePage(name,BACKGNDPAGE)
- END;
-
- PROCEDURE LoadBackgroundPage(name:STRING);
- { in: name = file name for the background picture to load}
- { BACKGNDPAGE= destination page, in which to load the picture (=2) }
- { PAGESIZE = size of one bitplane }
- { PICHeader= tag for picture files }
- {out: - }
- {rem: The bitmap-picture contained in file "name" has been loaded to the }
- { background page BACKGNDPAGE}
- { Using the routine only makes sense when using background mode STATIC}
- BEGIN
- LoadPage(name,BACKGNDPAGE)
- END;
-
- PROCEDURE FadeIn(pa,ti,style:WORD);
- { in: pa = page which shall be faded onto the actually visible page }
- { ti = time in milliseconds for this action }
- { style = algorithm which shall be used }
- { 1-PAGE = actually visible page }
- {out: Error = Err_InvalidFade, if illegal "style" value has been used }
- {rem: graphic mode must have been initialized already }
- { most often, you will use pa=BACKGNDPAGE }
-
- PROCEDURE WipeIn(pa,time:WORD);
- { in: pa = page, which contents will be made visible }
- { time = time (in millisceconds) for this action (approx.) }
- { 1-PAGE= (visible) graphic page on which to draw }
- {out: - }
- {rem: the contents of page "pa" has been copied to page 1-PAGE }
- CONST hoehe =40; {divisor of Succ(YMAX)}
- breite=40; {divisor of Succ(XMAX)}
- br_x =Succ(XMAX) DIV breite; {blocks in X-direction}
- br_y =Succ(YMAX) DIV hoehe; {blocks in Y-direction}
- n=hoehe*br_x; {number of executions of the delay loop }
- VAR i,x,y,ploty,plotx:WORD;
- counter:WORD;
- ClockTicks:LONGINT ABSOLUTE $40:$6C;
- t:LONGINT;
- temp:REAL;
- p:POINTER;
- BEGIN
- t:=ClockTicks;
- counter:=0;
- temp:=0.0182*time/n;
- FOR i:=0 TO pred(hoehe) DO
- FOR x:=0 TO pred(br_x) DO
- BEGIN
- FOR y:=0 TO pred(br_y) DO
- BEGIN
- IF ODD(x)
- THEN ploty:=y*hoehe+i +StartVirtualY
- ELSE ploty:=y*hoehe+(hoehe-1-i)+StartVirtualY;
- plotx:=x*breite +StartVirtualX;
- p:=GetImage(plotx,ploty,plotx+pred(breite),ploty,pa);
- PutImage(plotx,ploty,p,1-PAGE);
- FreeImageMem(p);
- END; {of FOR y}
- INC(counter);
- WHILE ClockTicks<t+counter*temp DO BEGIN END;
- END; {of FOR x}
- END;
-
- PROCEDURE Chaos(pa,time:WORD;m:BYTE);
- { in: pa = page, which contents will be made visible }
- { time = time (in millisceconds) for this action (approx.) }
- { m = the way how this shall be done (1..14)}
- { 1-PAGE= (visible) graphic page on which to draw }
- {out: - }
- {rem: the contents of page "pa" has been copied to page 1-PAGE }
- CONST n=Succ(XMAX)*Succ(YMAX); {number of screen pixels}
- {e.g., good values are sums of powers of 2 +1 }
- para:ARRAY[1..14] OF WORD=
- (13477,65,337,129,257,513,769,1025,481,4097,5121,177,16385,16897);
- VAR i,k,x,y:WORD;
- counter:WORD;
- ClockTicks:LONGINT ABSOLUTE $40:$6C;
- t:LONGINT;
- temp:REAL;
- rand:WORD;
- BEGIN
- t:=ClockTicks;
- counter:=0;
- rand:=0;
- IF (m<1) OR (m>14) THEN m:=1;
- k:=para[m];
- temp:=0.0182*time/n;
- FOR i:=0 TO 65535 DO
- BEGIN
- ASM {compute: "x:=rand MOD 320" and "y:=rand DIV 320" }
- XOR DX,DX
- MOV AX,rand
- MOV BX,XMAX+1
- DIV BX
- MOV y,AX
- MOV x,DX
- END;
- IF y<=YMAX
- THEN PutPixel(StartVirtualX+x,StartVirtualY+y,
- PageGetPixel(StartVirtualX+x,StartVirtualY+y,pa));
- ASM {compute: rand:=rand*k+1 }
- MOV AX,rand
- MUL k
- INC AX
- MOV rand,AX
- END;
- INC(counter);
- WHILE ClockTicks<t+counter*temp DO BEGIN END;
- END; {of FOR i}
- END;
-
- PROCEDURE SweepVertical(pa,time:WORD; down:BOOLEAN);
- { in: pa = page, which contents will be made visible }
- { time = time (in millisceconds) for this action (approx.) }
- { down = TRUE/FALSE for: from bottom to top/vice versa }
- { 1-PAGE= (visible) graphic page on which to draw }
- {out: - }
- {rem: the contents of page "pa" has been copied to page 1-PAGE }
- CONST n=Succ(YMAX); {number of executions of the delay loop }
- VAR y,counter:WORD;
- ClockTicks:LONGINT ABSOLUTE $40:$6C;
- t:LONGINT;
- temp:REAL;
- oldColor,step:BYTE;
- p:POINTER;
- BEGIN
- oldColor:=Color;
- Color:=white;
- t:=ClockTicks;
- counter:=0;
- temp:=0.0182*time/n;
- IF down
- THEN FOR y:=0+StartVirtualY TO YMAX+StartVirtualY DO
- BEGIN
- Line(StartVirtualX,y,StartVirtualX+XMAX,y,1-PAGE);
- INC(counter);
- WHILE ClockTicks<t+counter*temp DO BEGIN END;
- p:=GetImage(StartVirtualX,y,StartVirtualX+XMAX,y,pa);
- PutImage(StartVirtualX,y,p,1-PAGE);
- FreeImageMem(p);
- END
- ELSE FOR y:=YMAX+StartVirtualY DOWNTO 0+StartVirtualY DO
- BEGIN
- Line(StartVirtualX,y,StartVirtualX+XMAX,y,1-PAGE);
- INC(counter);
- WHILE ClockTicks<t+counter*temp DO BEGIN END;
- p:=GetImage(StartVirtualX,y,StartVirtualX+XMAX,y,pa);
- PutImage(StartVirtualX,y,p,1-PAGE);
- FreeImageMem(p);
- END;
- Color:=oldColor
- END;
-
- PROCEDURE SweepHorizontal(pa,time:WORD; left_to_right:BOOLEAN);
- { in: pa = page, which contents will be made visible }
- { time = time (in millisceconds) for this action (approx.) }
- { left_to_right=TRUE/FALSE for: from left to right/vice versa }
- { 1-PAGE= (visible) graphic page on which to draw }
- {out: - }
- {rem: the contents of page "pa" has been copied to page 1-PAGE }
- CONST n=Succ(XMAX); {number of executions of the delay loop }
- VAR x,counter:WORD;
- ClockTicks:LONGINT ABSOLUTE $40:$6C;
- t:LONGINT;
- temp:REAL;
- oldColor,step:BYTE;
- p:POINTER;
- BEGIN
- oldColor:=Color;
- Color:=white;
- t:=ClockTicks;
- counter:=0;
- temp:=0.0182*time/n;
- IF left_to_right
- THEN FOR x:=0+StartVirtualX TO XMAX+StartVirtualX DO
- BEGIN
- Line(x,StartVirtualY,x,StartVirtualY+YMAX,1-PAGE);
- INC(counter);
- WHILE ClockTicks<t+counter*temp DO BEGIN END;
- p:=GetImage(x,StartVirtualY,x,StartVirtualY+YMAX,pa);
- PutImage(x,StartVirtualY,p,1-PAGE);
- FreeImageMem(p);
- END
- ELSE FOR x:=XMAX+StartVirtualX DOWNTO 0+StartVirtualX DO
- BEGIN
- Line(x,StartVirtualY,x,StartVirtualY+YMAX,1-PAGE);
- INC(counter);
- WHILE ClockTicks<t+counter*temp DO BEGIN END;
- p:=GetImage(x,StartVirtualY,x,StartVirtualY+YMAX,pa);
- PutImage(x,StartVirtualY,p,1-PAGE);
- FreeImageMem(p);
- END;
- Color:=oldColor
- END;
-
- PROCEDURE ScrollVertical(pa,time:WORD; up:BOOLEAN);
- { in: pa = page, which contents will be made visible }
- { time = time (in millisceconds) for this action (approx.) }
- { up = TRUE/FALSE for: from bottom to top/vice versa }
- { 1-PAGE= (visible) graphic page on which to draw }
- {out: - }
- {rem: the contents of page "pa" has been copied to page 1-PAGE }
- LABEL oneLine1,oneLine2;
- CONST n=Succ(YMAX); {number of executions of the delay loop }
- VAR counter:WORD;
- ClockTicks:LONGINT ABSOLUTE $40:$6C;
- t:LONGINT;
- temp:REAL;
- BEGIN
- t:=ClockTicks;
- counter:=0;
- temp:=0.0182*time/n;
- IF up
- THEN BEGIN {scroll upwards }
- ASM
- MOV DX,3C4h
- MOV AX,0F02h {access all 4 planes at once }
- OUT DX,AX
- MOV DX,3CEh
- MOV AX,4105h {set write mode 1 }
- OUT DX,AX
-
- MOV SI,1
- SUB SI,PAGE
- AND SI,1
- SHL SI,1
- ADD SI,OFFSET Segment_Adr-StartIndex*2
- LODSW
- MOV ES,AX {ES:=Segment_Adr[1-PAGE] = ^visible page }
-
- MOV SI,pa
- AND SI,3
- SHL SI,1
- ADD SI,OFFSET Segment_Adr-StartIndex*2
- LODSW {AX:=Segment_Adr[pa] = ^source address}
-
- PUSH DS
- MOV DX,AX
- MOV BX,YMAX*LINESIZE+(LINESIZE-1) {DX:BX = ^source data}
-
- MOV AX,YMAX {AX = row counter }
-
- oneLine2:
- STD {move backwards! }
- MOV SI,ES {first scroll old contents upwards: }
- MOV DS,SI {DS=ES=visible graphic page }
- MOV SI,(YMAX-1)*LINESIZE+(LINESIZE-1) {from last but one graphic row}
- MOV DI,YMAX*LINESIZE+(LINESIZE-1) {to last graphic row }
- MOV CX,YMAX*LINESIZE {199 rows }
- REP MOVSB
-
- MOV DS,DX {now make new row visible: }
- MOV SI,BX {DS:SI=^row to move }
- MOV CX,LINESIZE {1 row }
- REP MOVSB
-
- SUB BX,LINESIZE {increase source pointer }
-
- {--- insertion to realize timing:}
- PUSH AX {save all registers needed later }
- PUSH BX
- PUSH DX
- PUSH ES
- MOV AX,SEG @DATA {restore TP's data segment }
- MOV DS,AX
- CLD {just to be sure! }
- END;
- INC(counter);
- WHILE ClockTicks<t+counter*temp DO BEGIN END;
- ASM;
- POP ES
- POP DX
- POP BX
- POP AX
- {--- end of insertion}
-
- DEC AX {all rows done? }
- JNS oneLine2 {no, next row }
-
- MOV DX,3CEh {restore write mode 0 }
- MOV AX,4005h
- OUT DX,AX
- POP DS
- END;
- END
- ELSE BEGIN {scroll downwards }
- ASM
- MOV DX,3C4h
- MOV AX,0F02h {access all 4 planes at once }
- OUT DX,AX
- MOV DX,3CEh
- MOV AX,4105h {set write mode 1 }
- OUT DX,AX
-
- MOV SI,1
- SUB SI,PAGE
- AND SI,1
- SHL SI,1
- ADD SI,OFFSET Segment_Adr-StartIndex*2
- LODSW
- MOV ES,AX {ES:=Segment_Adr[1-PAGE] = ^visible page }
-
- MOV SI,pa
- AND SI,3
- SHL SI,1
- ADD SI,OFFSET Segment_Adr-StartIndex*2
- LODSW {AX:=Segment_Adr[pa] = ^source address}
-
- PUSH DS
- MOV DX,AX
- MOV BX,0*LINESIZE {DX:BX = ^source data}
-
- MOV AX,YMAX {AX = row counter }
-
- oneLine1:
- MOV SI,ES {first scroll old contents upwards: }
- MOV DS,SI {DS=ES=visible graphic page }
- MOV SI,1*LINESIZE {from graphic row 1}
- MOV DI,0*LINESIZE {to graphic row 0 }
- MOV CX,YMAX*LINESIZE {199 rows }
- REP MOVSB
-
- MOV DS,DX {now make new row visible: }
- MOV SI,BX {DS:SI=^row to move }
- MOV CX,LINESIZE {1 row }
- REP MOVSB
-
- ADD BX,LINESIZE {increase source pointer }
-
- {--- insertion to realize timing:}
- PUSH AX {save all registers needed later }
- PUSH BX
- PUSH DX
- PUSH ES
- MOV AX,SEG @DATA {restore TP's data segment }
- MOV DS,AX
- END;
- INC(counter);
- WHILE ClockTicks<t+counter*temp DO BEGIN END;
- ASM;
- POP ES
- POP DX
- POP BX
- POP AX
- {--- end of insertion}
-
- DEC AX {all rows done? }
- JNS oneLine1 {no, next row }
-
- MOV DX,3CEh {restore write mode 0 }
- MOV AX,4005h
- OUT DX,AX
- POP DS
- END;
- END;
- END;
-
- PROCEDURE ScrollHorizontal(pa,time:WORD; left:BOOLEAN);
- { in: pa = page, which contents will be made visible }
- { time = time (in millisceconds) for this action (approx.) }
- { left = TRUE/FALSE for: from left to right/vice versa }
- { 1-PAGE= (visible) graphic page on which to draw }
- {out: - }
- {rem: the contents of page "pa" has been copied to page 1-PAGE }
- LABEL oneColumn1,oneColumn2;
- CONST n=Pred(LINESIZE); {number of executions of the delay loop }
- VAR counter:WORD;
- ClockTicks:LONGINT ABSOLUTE $40:$6C;
- t:LONGINT;
- temp:REAL;
- BEGIN
- t:=ClockTicks;
- counter:=0;
- temp:=0.0182*time/n;
- IF left
- THEN BEGIN {scroll to the left }
- ASM
- MOV DX,3C4h
- MOV AX,0F02h {access all 4 planes at once }
- OUT DX,AX
- MOV DX,3CEh
- MOV AX,4105h {set write mode 1 }
- OUT DX,AX
-
- MOV SI,1
- SUB SI,PAGE
- AND SI,1
- SHL SI,1
- ADD SI,OFFSET Segment_Adr-StartIndex*2
- LODSW
- MOV ES,AX {ES:=Segment_Adr[1-PAGE] = ^visible page }
-
- MOV SI,pa
- AND SI,3
- SHL SI,1
- ADD SI,OFFSET Segment_Adr-StartIndex*2
- LODSW {AX:=Segment_Adr[pa] = ^source address}
-
- PUSH DS
- MOV DX,AX
- MOV BX,0*LINESIZE+0 {DX:BX = ^source data}
-
- MOV AX,LINESIZE-1 {AX = column counter}
-
- oneColumn2: {scroll old screen contents to the right:}
- MOV SI,ES
- MOV DS,SI {DS = ES = visible graphic page }
- MOV SI,PAGESIZE-2
- MOV DI,PAGESIZE-1
- MOV CX,PAGESIZE-1
- STD
- REP MOVSB
- CLD
-
- MOV CX,SEG @DATA
- MOV DS,CX {DS = ^TP's data}
- MOV CX,YMAX+1 {CX = row counter }
-
- MOV SI,AX
- XOR DI,DI
- MOV BX,LINESIZE-1
- MOV DS,DX {DS = ^source data}
-
- @oneRow: {update first column: }
- MOVSB
- ADD SI,BX {position at next row: }
- ADD DI,BX {works, because BX+1=LINESIZE}
- LOOP @oneRow
-
- {--- insertion to realize timing:}
- PUSH AX {save all registers needed later }
- PUSH DX
- PUSH ES
- MOV AX,SEG @DATA {restore TP's data segment }
- MOV DS,AX
- END;
- INC(counter);
- WHILE ClockTicks<t+counter*temp DO BEGIN END;
- ASM;
- POP ES
- POP DX
- POP AX
- {--- end of insertion}
-
- DEC AX {all columns done? }
- JNS oneColumn2 {no, next column }
-
- MOV DX,3CEh {restore write mode 0 }
- MOV AX,4005h
- OUT DX,AX
- POP DS
- END;
- END
- ELSE BEGIN {scroll to the right }
- ASM
- MOV DX,3C4h
- MOV AX,0F02h {access all 4 planes at once }
- OUT DX,AX
- MOV DX,3CEh
- MOV AX,4105h {set write mode 1 }
- OUT DX,AX
-
- MOV SI,1
- SUB SI,PAGE
- AND SI,1
- SHL SI,1
- ADD SI,OFFSET Segment_Adr-StartIndex*2
- LODSW
- MOV ES,AX {ES:=Segment_Adr[1-PAGE] = ^visible page }
-
- MOV SI,pa
- AND SI,3
- SHL SI,1
- ADD SI,OFFSET Segment_Adr-StartIndex*2
- LODSW {AX:=Segment_Adr[pa] = ^source address}
-
- PUSH DS
- MOV DX,AX
- MOV BX,0*LINESIZE+0 {DX:BX = ^source data}
-
- MOV AX,0 {AX = column counter}
-
- oneColumn1: {scroll old screen contents to the left:}
- MOV SI,ES
- MOV DS,SI {DS = ES = visible graphic page }
- MOV SI,1
- XOR DI,DI
- MOV CX,PAGESIZE-1
- REP MOVSB
-
- MOV CX,SEG @DATA
- MOV DS,CX {DS = ^TP's data}
- MOV CX,YMAX+1 {CX = row counter }
-
- MOV SI,AX
- MOV DI,LINESIZE-1
- MOV BX,LINESIZE-1
- MOV DS,DX {DS = ^source data}
-
- @oneRow: {update last column: }
- MOVSB
- ADD SI,BX {position at next row: }
- ADD DI,BX {works, because BX+1=LINESIZE}
- LOOP @oneRow
-
- {--- insertion to realize timing:}
- PUSH AX {save all registers needed later }
- PUSH DX
- PUSH ES
- MOV AX,SEG @DATA {restore TP's data segment }
- MOV DS,AX
- END;
- INC(counter);
- WHILE ClockTicks<t+counter*temp DO BEGIN END;
- ASM;
- POP ES
- POP DX
- POP AX
- {--- end of insertion}
-
- INC AX {all columns done? }
- CMP AX,LINESIZE
- JB oneColumn1 {no, next column }
-
- MOV DX,3CEh {restore write mode 0 }
- MOV AX,4005h
- OUT DX,AX
- POP DS
- END;
- END;
- END;
-
- PROCEDURE CircleIn(pa,time:WORD);
- { in: pa = page, which contents will be made visible }
- { time = time (in millisceconds) for this action (approx.) }
- {out: - }
- {rem: the contents of page "pa" has been copied to page 1-PAGE }
- CONST centerX=XMAX DIV 2; {middle of screen}
- centerY=YMAX DIV 2;
- k=189; {number of circles:= sqrt(centerX²+centerY²), rounded up}
- adjust=0.707106781; {compensation in diagonal direction = 1/sqrt(2) }
- n=TRUNC(k/adjust); {number of executions of the delay loop }
- VAR radqu,x,y,x0,y0,u1,u2,u3,u4,v1,v2,v3,v4:WORD;
- counter:WORD;
- ClockTicks:LONGINT ABSOLUTE $40:$6C;
- t:LONGINT;
- radius,temp:REAL;
- BEGIN
- t:=ClockTicks;
- counter:=0;
- temp:=0.0182*time/n;
- x0:=centerX + StartVirtualX;
- y0:=centerY + StartVirtualY;
- {unfortunately, FOR true_radius:=1 TO k STEP 1/adjust isn't possible in TP }
- radius:=0.0;
- REPEAT
- radqu:=TRUNC(sqr(radius));
- FOR x:=0 TO TRUNC(radius/sqrt(2)) DO {compute octant }
- BEGIN
- y:=TRUNC(sqrt(radqu-sqr(x))); {Pythagorean proposition}
- u1:=x0-x; v1:=y0-y; {use axial- and point symmetrie }
- u2:=x0+x; v2:=y0+y;
- u3:=x0-y; v3:=y0-x;
- u4:=x0+y; v4:=y0+x;
- PutPixel(u1,v1,PageGetPixel(u1,v1,pa));
- PutPixel(u1,v2,PageGetPixel(u1,v2,pa));
- PutPixel(u2,v1,PageGetPixel(u2,v1,pa));
- PutPixel(u2,v2,PageGetPixel(u2,v2,pa));
- PutPixel(u3,v3,PageGetPixel(u3,v3,pa));
- PutPixel(u3,v4,PageGetPixel(u3,v4,pa));
- PutPixel(u4,v3,PageGetPixel(u4,v3,pa));
- PutPixel(u4,v4,PageGetPixel(u4,v4,pa));
- END;
- radius:=radius+adjust;
- INC(counter);
- WHILE ClockTicks<t+counter*temp DO BEGIN END;
- UNTIL radius>=k;
- END;
-
- BEGIN {of FadeIn}
- IF (pa<>0) AND (pa<>1) AND (pa<>BACKGNDPAGE)
- THEN Error:=Err_InvalidPageNumber
- ELSE CASE style OF
- Fade_Squares :WipeIn(pa,ti);
- Fade_Moiree1..Fade_Moiree14:Chaos(pa,ti,style+1-Fade_Moiree1);
- Fade_SweepInFromTop: SweepVertical(pa,ti,TRUE);
- Fade_SweepInFromBottom: SweepVertical(pa,ti,FALSE);
- Fade_SweepInFromLeft: SweepHorizontal(pa,ti,TRUE);
- Fade_SweepInFromRight: SweepHorizontal(pa,ti,FALSE);
- Fade_ScrollInFromTop: ScrollVertical(pa,ti,TRUE);
- Fade_ScrollInFromBottom:ScrollVertical(pa,ti,FALSE);
- Fade_ScrollInFromLeft: ScrollHorizontal(pa,ti,TRUE);
- Fade_ScrollInFromRight: ScrollHorizontal(pa,ti,FALSE);
- Fade_Circles : CircleIn(pa,ti);
- else Error:=Err_InvalidFade
- END;
- END;
-
-
- PROCEDURE InitRoutines;
- { in: - }
- {out: SpriteN[],SPRITEAD[] have been initialized to "completely empty" }
- { NextSprite[] has been set in such a way that every sprite is its }
- { own successor}
- { PAGE, PAGEADR have been set to graphic page 0 }
- { BACKGNDADR has been set to the background page }
- { SCROLLADR has been set to the scrollable background page }
- { BACKGROUNDMODE has been set to STATIC }
- { tile #0 has been set as default tile for scrollable background }
- { StartVirtualX,StartVirtualY =0 (that is: virtual = absolute coord.)}
- { oldMode = old graphicmode }
- { Error has been set, if no VGA-card could be found in the system }
- { CycleTime = 0, that is: no min. time for animation cycle }
- { Color = 15, that is: white }
- { ActualColors = default color palette of mode $13 }
- { CRTAddress = port address of CRT-address register}
- { StatusReg = port address of state register }
- {rem: This procedure should be called only once - namely in the very }
- { beginning - for initializing the whole package properly }
- VAR i:WORD;
-
- FUNCTION IsVGA:BOOLEAN;
- BEGIN
- WITH Regs DO
- BEGIN
- AX:=$1A00;
- Intr($10,Regs);
- IsVGA:=(AL=$1A) AND {VGA's identify-adapter-function supported? }
- ( (BL=7) OR (BL=8) ) {monochrome or color VGA - adapter}
- END;
- END;
-
- BEGIN
- IF IsVGA THEN Error:=Err_None
- ELSE Error:=Err_NoVGA;
-
- SetCycleTime(0);
-
- fillchar(SpriteN,sizeof(SpriteN),0);
- fillchar(SPRITEAD,sizeof(SPRITEAD),0);
-
- FOR i:=0 TO LoadMAX DO NextSprite[i]:=i;
-
- BACKGNDADR:=Segment_Adr[BACKGNDPAGE]; {segment address of background page }
-
- PAGE:=0; {page to be drawn upon }
- PAGEADR:=Segment_Adr[PAGE];
- SCROLLADR:=Segment_Adr[SCROLLPAGE];
- SetBackgroundMode(STATIC);
- SetOffscreenTile(0);
-
- StartVirtualX:=0; StartVirtualY:=0; {virtual = absolute coordinates }
- Color:=white; {set actual drawing color to white }
- regs.ah:=$f; intr($10,regs); oldMode:=regs.al;
-
- ActualColors:=DefaultColors;
- {SetShadowTab(Schatten) isn't needed, as the default values are set already}
-
- ASM {see if we are using color-/monochorme display}
- MOV DX,3CCh {use output register: }
- IN AL,DX
- TEST AL,1 {is it a color display? }
- MOV DX,3D4h
- JNZ @L1 {yes }
- MOV DX,3B4h {no }
- @L1: {DX=3B4h/3D4h = CRTAddress-register for monochrome/color}
- MOV CRTAddress,DX
- ADD DX,6 {DX=3BAh/3DAh = state register for monochrome/color }
- MOV StatusReg,DX
- END; {of ASM}
- END;
-
- PROCEDURE CloseRoutines;
- { in: oldMode = old graphicmode, to which we'll switch back }
- {out: - }
- BEGIN
- regs.al:=oldMode; regs.ah:=0; intr($10,regs);
- END;
-
- FUNCTION GetErrorMessage:STRING;
- { in: Error = number of the occurred error }
- {out: the error described in words}
- BEGIN
- CASE Error OF
- Err_None:GetErrorMessage:='No Error';
- Err_NotEnoughMemory:GetErrorMessage:='Not enough memory available on heap';
- Err_FileIO:GetErrorMessage:='I/O-error with file';
- Err_InvalidSpriteNumber:GetErrorMessage:='Invalid sprite number used';
- Err_NoSprite:GetErrorMessage:='No (or corrupted) sprite file';
- Err_InvalidPageNumber:GetErrorMessage:='Invalid page number used';
- Err_NoVGA:GetErrorMessage:='No VGA-card found';
- Err_NoPicture:GetErrorMessage:='No (or corrupted) picture file';
- Err_InvalidPercentage:GetErrorMessage:='Percentage value must be 0..100';
- Err_NoTile:GetErrorMessage:='No (or corrupted) tile/sprite file';
- Err_InvalidTileNumber:GetErrorMessage:='Invalid tile number used';
- Err_InvalidCoordinates:GetErrorMessage:='Invalid coordinates used';
- Err_BackgroundToBig:GetErrorMessage:='Background to big for tile-buffer';
- Err_InvalidMode:GetErrorMessage:='Only STATIC or SCROLLING allowed here';
- Err_InvalidSpriteLoadNumber:GetErrorMessage:='Invalid spriteload number used';
- Err_NoPalette:GetErrorMessage:='No (or corrupted) palette file';
- Err_PaletteWontFit:GetErrorMessage:='Attempt to write beyond palette end';
- Err_InvalidFade:GetErrorMessage:='Invalid fade style used';
- ELSE GetErrorMessage:='Unknown error';
- END;
- END;
-
-
- BEGIN
-
- InitRoutines;
-
- END.
-